Bug 14346 – is-expression dependent on instantiation order
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2015-03-26T15:59:47Z
Last change time
2022-02-14T15:46:01Z
Keywords
wrong-code
Assigned to
No Owner
Creator
Marc Schütz
Comments
Comment #0 by schuetzm — 2015-03-26T15:59:47Z
This is a really weird bug. Here's how far I could reduce it:
struct Validate() {
this(string ) {
}
}
template isConvertibleToInstanceOf(alias From, alias To)
{
enum isConvertibleToInstanceOf = isConvertibleToInstanceOf!(typeof(From), To);
}
template isConvertibleToInstanceOf(From, alias To)
{
enum isConvertibleToInstanceOf =
is(From : To!Args, Args...);
}
template Validation() {
void validate() {
// run validators for members
foreach(member; __traits(allMembers, typeof(this))) {
foreach(UDA; __traits(getAttributes, mixin(member))) {
// THE FOLLOWING LINE IS MAGIC
static if(isConvertibleToInstanceOf!(UDA, Validate)) { }
// ---------------------------
}
}
// run validators for entire object
foreach(UDA; __traits(getAttributes, typeof(this))) {
// THE RESULT OF THIS IS-EXPR DEPENDS ON THE LINE ABOVE:
static if(isConvertibleToInstanceOf!(UDA, Validate))
pragma(msg, "isConvertibleToInstanceOf: ", typeof(UDA));
}
}
}
struct EmbeddedType { }
EmbeddedType Embedded;
@Embedded
class Address {
@Validate!()("invalid country")
string country;
mixin Validation;
}
When the first `static if` is there, the `pragma` prints "isConvertibleToInstanceOf: EmbeddedType". But if it is removed or commented out, the `pragma` isn't called; evidently the second `static if` fails.
Comment #1 by ketmar — 2015-03-26T23:19:30Z
seems that there is some bug with template merging. change your template declarations to this:
template isConvertibleToInstanceOf(alias From, alias To, usize dummy=__LINE__)
template isConvertibleToInstanceOf(From, alias To, usize dummy=__LINE__)
and you will never see pragma output from second `static if`.
Comment #2 by ketmar — 2015-03-26T23:19:54Z
ah. `usize` is simply an alias for `size_t`. sorry.
Comment #3 by ag0aep6g — 2015-04-25T20:58:28Z
Reduced further:
----
template typeOf(alias From)
{
alias typeOf = typeof(From);
}
string val;
int embedded;
void main()
{
foreach(UDA; Tuple!val)
{
pragma(msg, typeOf!UDA); /* prints "string", ok */
}
foreach(UDA; Tuple!embedded)
{
/* THE RESULT OF THIS DEPENDS ON THE LINE ABOVE: */
pragma(msg, typeOf!UDA); /* prints "string", should print "int" */
}
}
alias Tuple(stuff ...) = stuff;
----
This is very similar to issue 14501.
Comment #4 by razvan.nitu1305 — 2022-02-14T15:46:01Z
(In reply to ag0aep6g from comment #3)
> Reduced further:
>
> ----
> template typeOf(alias From)
> {
> alias typeOf = typeof(From);
> }
>
> string val;
> int embedded;
>
> void main()
> {
> foreach(UDA; Tuple!val)
> {
> pragma(msg, typeOf!UDA); /* prints "string", ok */
> }
> foreach(UDA; Tuple!embedded)
> {
> /* THE RESULT OF THIS DEPENDS ON THE LINE ABOVE: */
> pragma(msg, typeOf!UDA); /* prints "string", should print "int" */
> }
> }
>
> alias Tuple(stuff ...) = stuff;
> ----
>
> This is very similar to issue 14501.
When running the above code the second pragma prints int as expected. It seems that this has been fixed.