DMD 2.058 accepted the following snippet, while DMD c2824d43 executes the else branch of the static if. In there, though, instantiating the template will (apparently) just work fine.
---
mixin template Helpers() {
alias typeof(this) This;
static if (is(Flags!This)) {
Flags!This flags;
} else {
// DMD will happily instantiate the allegedly
// non-existent Flags!This here. (!)
pragma(msg, __traits(derivedMembers, Flags!This));
}
}
template Flags(T) {
mixin({
string defs;
foreach (name; __traits(derivedMembers, T)) {
defs ~= "bool " ~ name ~ ";\n";
}
if (defs.length > 0) {
return "struct Flags {" ~ defs ~ "}";
} else {
return "";
}
}());
}
struct Move {
int a;
mixin Helpers!();
}
enum a = Move.init.flags; // isSetFlags should exist.
---
(Note that while the above code is probably not the minimal possible example needed to trigger the bug, it has been reduced beyond repair as far as its original intent goes, so don't try to make sense of it in that regard.)
Comment #1 by github-bugzilla — 2012-04-05T21:07:38Z
I think the fix may have only fixed certain cases of this bug. I'm running into another case of what looks to be the same bug using 2.059 beta 2, but I'm still working on reducing it.
Comment #3 by dsimcha — 2012-04-07T17:22:21Z
I reduced the case where it's still failing, reopened.
enum Closure {
Matrix
}
struct BasicMatrix {
mixin Operand!( Closure.Matrix );
}
template Operand( Closure closure_ ) {
alias closure_ closure;
}
struct Expression( string op_, Lhs, Rhs = void ) {
enum lhsClosure = closureOf!Lhs;
}
template closureOf( T ) {
enum closureOf = T.closure;
}
alias Expression!("+", BasicMatrix) Foo;
test.d(18): Error: no property 'closure' for type 'BasicMatrix'
test.d(14): Error: template instance test.closureOf!(BasicMatrix) error instantiating
test.d(21): instantiated from here: Expression!("+",BasicMatrix)
test.d(21): Error: template instance test.Expression!("+",BasicMatrix) error instantiating
Comment #4 by bugzilla — 2012-04-07T18:06:42Z
Please, the original two bugs were fixed and are fixed. A new bug should entered for new bugs, not reopening fixed ones. For next time.
Comment #5 by bugzilla — 2012-04-07T18:18:42Z
This new case fails also on dmd 2.058, so it is not a regression.
Comment #6 by bugzilla — 2012-04-07T18:19:31Z
Reduced test case:
-----------------------
enum Closure {
Matrix
}
struct BasicMatrix {
mixin Operand!( Closure.Matrix );
}
template Operand( Closure closure_ ) {
alias closure_ closure;
}
alias BasicMatrix.closure Foo;
Comment #7 by github-bugzilla — 2012-04-07T18:56:07Z
The fix that was just checked in fixes the test case I submitted but doesn't fix the bug in the code that I reduced the test case from. I'm working on reducing another test case that still fails.
Comment #9 by code — 2012-04-08T10:10:43Z
The original code I reduced the test case from still doesn't work either, will report a new bug once I managed to reduce it again.
Comment #10 by dsimcha — 2012-04-08T11:55:35Z
Created attachment 1085
A not-very-reduced test case.
I'll try harder to reduce this later if necessary, but I don't have time right now and every time someone reduces this bug it seems like something important gets left out. Here's a zip file of my mostly unreduced. Just go into the main directory (bug7815/) and do a dmd test.d. This will instantiate all the necessary templates to reproduce the bug even on 2.059 Beta 3. Hopefully this will be easier to reduce for someone who has a better understanding of what changed between releases.
Comment #11 by code — 2012-04-08T15:13:41Z
Issue 7862 might be related to what I'm seeing.
Comment #12 by dsimcha — 2012-04-09T07:31:57Z
Created attachment 1086
DMD 2.059 Beta 4 testcase
Here's a new test case that works around a change in Phobos that apparently occurred between betas. This reproduces the failure on DMD 2.059 Beta 4. Usage is the same as the old test case.
Comment #13 by bugzilla — 2012-04-10T10:19:52Z
Created attachment 1088
reduced test.d and scid/matrix.d
this replaces the files scid/matrix.d and test.d in the test case. They are somewhat reduced.
Comment #14 by code — 2012-04-10T22:38:19Z
Drastically reduced test case:
———
struct Expression(string op_, Lhs) {
enum lhsClosure = closureOf!Lhs;
}
template closureOf(T) {
static if (is(typeof({
T x;
x + x;
}))) {}
enum closureOf = 1;
}
struct BasicVector {
void t() {
auto r = Expression!("t", typeof(this))();
}
auto opBinary( string op, NewRhs )( NewRhs ) {
return Expression!("+", typeof(this))();
}
}
———
Comment #15 by bugzilla — 2012-04-11T10:40:51Z
I reduced the test case a little more:
struct Expression(int op) {
enum lhsClosure = closureOf!();
}
template closureOf() {
static if (is(typeof({
BasicVector x;
x.bar(x);
}))) {}
enum closureOf = 1;
}
struct BasicVector {
void t() {
auto r = Expression!(1)();
}
void bar(T)(T) {
auto x = Expression!(2)();
}
}
Comment #16 by bugzilla — 2012-04-11T10:49:07Z
Ok, here's the problem.
Attempt to compile BasicVector.
Expand Expression!(1)().
Expand closureOf!() which is needed to initialize lhsClosure.
1. closureOf has two members 1. the static if 2. the enum closureOf
2. in order to initialize lhsClosure, closureOf must be eponymous
therefore, we must evaluate the static if.
Evaluating the static if evaluates bar(T)(T)
bar(T)(T) evaluates Expression!(2)()
Expression!(2)() needs to eponymously expand closureOf!()
And so we wind up in a circle, hence the confusing error message.
It "worked" prior because the circular reference error was ignored.
Comment #17 by github-bugzilla — 2012-04-11T14:43:23Z
Comment #18 by github-bugzilla — 2015-05-13T21:38:17Z
Commit pushed to master at https://github.com/D-Programming-Language/dmdhttps://github.com/D-Programming-Language/dmd/commit/d0c854a1722c286777c5e48e0780e5318a986f49
Move issue 7815 case to fail_compilation, because it was invalid
It was wrongly accepted by the bug in `StaticIfCondition::include()`.
Bug explanation copied from fail_compilation/fail7815.d:
----
When the Move struct member is analyzed:
1. mixin Helpers!() is instantiated.
2. In Helpers!(), static if and its condition is(Flags!Move)) evaluated.
3. In Flags!Move, string mixin evaluates and CTFE lambda.
4. __traits(derivedMembers, Move) tries to see the member of Move.
4a. mixin Helpers!() member is analyzed.
4b. `static if (is(Flags!Move))` in Helpers!() is evaluated
4c. The Flags!Move instantiation is already in progress, so it cannot be resolved.
4d. `static if` fails because Flags!Move cannot be determined as a type.
5. __traits(derivedMembers, Move) returns a 1-length tuple("a").
6. The lambda in Flags!Move returns a string "struct Flags {...}", then
Flags!Move is instantiated to a new struct Flags.
7. Finally Move struct does not have flags member, then the `enum a7815`
definition will fail in its initializer.
Comment #19 by github-bugzilla — 2015-06-17T21:05:06Z