One of the weirdest bugs I've ever encountered. Set up a directory named 'basic'. Inside there 3 files: module basic.Messages; //import basic.utils; // for flattenNamedEnum pragma(msg, "foo"); enum Severity { NOTE, } pragma(msg, flattenNamedEnum!Severity); pragma(msg, "bar"); // definition of enum Msg is normally mixed in here ==== module basic.Bar; import basic.Handle; import basic.Messages; class Bar { public: enum Level { Ignored, } void bla(Msg msg) { } } ==== module basic.Handle; import basic.Bar; void foo(Bar.Level level) { } I compiled it from inside the folder with 'dmd -c -I.. Bar.d Handle.d' Bar.d(13): Error: undefined identifier Msg foo Note how basic.Messages is only evaluated to a certain degree. The same happens with dmd -c -I.. Bar.d Handle.d Messages.d dmd -c -I.. Bar.d Messages.d Handle.d Only with 'dmd -c -I.. Handle.d Bar.d' it yields foo ../basic/Messages.d(14): Error: template instance template 'flattenNamedEnum' is not defined __error bar Bar.d(16): Error: undefined identifier Msg And with 'dmd -c -I.. Messages.d Bar.d Handle.d': foo Messages.d(14): Error: template instance template 'flattenNamedEnum' is not defined __error bar Bar.d(16): Error: undefined identifier Msg Also note that adding the definition of Msg by hand like enum Msg { f } or commenting out the flattenNamedEnum mixin also shows similar results. Can anyone confirm this?
Well, if ever needed, here's basic.utils: //! bring named enum members into current scope string flattenNamedEnum(EnumType)() if (is (EnumType == enum)) { string s = ""; foreach (i, e; __traits(allMembers, EnumType)) { s ~= "alias " ~ EnumType.stringof ~ "." ~ __traits(allMembers, EnumType)[i] ~ " " ~ __traits(allMembers, EnumType)[i] ~ ";\n"; } return s; } Pulling enum Level out of Bar also seems to 'resolve' this.
And for completeness the Msg generation from basic.Messages: private immutable records = [ ["bla", "blub"], ]; mixin (generateMsgEnum()); private string generateMsgEnum() { string res = " enum Msg : string\n{\n"; foreach (msg; .messageRecords) res ~= " " ~ msg[0] ~ " = `" ~ msg[1] ~ "`,\n"; res ~= "}\n"; return res; }
If this has to do with dmd exiting early because of errors, why is there no "fatal error: too many errors occured"? If it has to do with the cyclic import, why is Messages affected by that? In the import graph it is a sink (or source, depending on how you define the directions). (Of course utils will be the sink if you include it, but that doesn't change much)
I don't know when this has been fixed, but with 2.080.0, I get both error messages in all cases: dmd -c -I.. Bar.d Handle.d Bar.d(13): Error: undefined identifier Msg foo ../basic/Messages.d(11): Error: template instance `flattenNamedEnum!Severity` template flattenNamedEnum is not defined ../basic/Messages.d(11): while evaluating pragma(msg, flattenNamedEnum!Severity) bar dmd -c -I.. Bar.d Handle.d Messages.d Bar.d(13): Error: undefined identifier Msg foo Messages.d(11): Error: template instance `flattenNamedEnum!Severity` template flattenNamedEnum is not defined Messages.d(11): while evaluating pragma(msg, flattenNamedEnum!Severity) bar dmd -c -I.. Bar.d Messages.d Handle.d Bar.d(13): Error: undefined identifier Msg foo Messages.d(11): Error: template instance `flattenNamedEnum!Severity` template flattenNamedEnum is not defined Messages.d(11): while evaluating pragma(msg, flattenNamedEnum!Severity) bar dmd -c -I.. Handle.d Bar.d foo ../basic/Messages.d(11): Error: template instance `flattenNamedEnum!Severity` template flattenNamedEnum is not defined ../basic/Messages.d(11): while evaluating pragma(msg, flattenNamedEnum!Severity) bar Bar.d(13): Error: undefined identifier Msg dmd -c -I.. Bar.d Messages.d Handle.d Bar.d(13): Error: undefined identifier Msg foo Messages.d(11): Error: template instance `flattenNamedEnum!Severity` template flattenNamedEnum is not defined Messages.d(11): while evaluating pragma(msg, flattenNamedEnum!Severity) bar As this seems to work correctly, I'm closing this.
Please use WORKSFORME as resolution when you see it works now but don't know exactly why or which PR solved the issue.