diff --git a/src/declaration.d b/src/declaration.d index feb3b0eb5323..0be3e05dd334 100644 --- a/src/declaration.d +++ b/src/declaration.d @@ -1949,39 +1949,44 @@ extern (C++) class VarDeclaration : Declaration _init = _init.semantic(sc, type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); inuse--; } - if (storage_class & STCmanifest) + if (_init && storage_class & STCmanifest) { - version (none) + /* Cannot initializer enums with CTFE classreferences and addresses of struct literals. + * Scan initializer looking for them. Issue error if found. + */ + if (ExpInitializer ei = _init.isExpInitializer()) { - if ((type.ty == Tclass) && type.isMutable()) + static bool hasInvalidEnumInitializer(Expression e) { - error("is mutable. Only const and immutable class enum are allowed, not %s", type.toChars()); - } - else if (type.ty == Tpointer && type.nextOf().ty == Tstruct && type.nextOf().isMutable()) - { - ExpInitializer ei = _init.isExpInitializer(); - if (ei.exp.op == TOKaddress && (cast(AddrExp)ei.exp).e1.op == TOKstructliteral) + static bool arrayHasInvalidEnumInitializer(Expressions* elems) { - error("is a pointer to mutable struct. Only pointers to const or immutable struct enum are allowed, not %s", type.toChars()); + foreach (e; *elems) + { + if (e && hasInvalidEnumInitializer(e)) + return true; + } + return false; } - } - } - else - { - if (type.ty == Tclass && _init) - { - ExpInitializer ei = _init.isExpInitializer(); - if (ei.exp.op == TOKclassreference) - error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead."); - } - else if (type.ty == Tpointer && type.nextOf().ty == Tstruct) - { - ExpInitializer ei = _init.isExpInitializer(); - if (ei && ei.exp.op == TOKaddress && (cast(AddrExp)ei.exp).e1.op == TOKstructliteral) + + if (e.op == TOKclassreference) + return true; + if (e.op == TOKaddress && (cast(AddrExp)e).e1.op == TOKstructliteral) + return true; + if (e.op == TOKarrayliteral) + return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements); + if (e.op == TOKstructliteral) + return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements); + if (e.op == TOKassocarrayliteral) { - error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead."); + AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e; + return arrayHasInvalidEnumInitializer(ae.values) || + arrayHasInvalidEnumInitializer(ae.keys); } + return false; } + + if (hasInvalidEnumInitializer(ei.exp)) + error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead."); } } else if (_init && isThreadlocal()) diff --git a/test/compilable/interpret3.d b/test/compilable/interpret3.d index a4b6da798c96..9340241cf477 100644 --- a/test/compilable/interpret3.d +++ b/test/compilable/interpret3.d @@ -2692,11 +2692,6 @@ enum arr12528V2 = dup12528([0, 1]); static assert(arr12528V1 == [0]); static assert(arr12528V2 == [0, 1]); -enum arr12528C1 = dup12528([new immutable Object]); -enum arr12528C2 = dup12528([new immutable Object, new immutable Object]); -static assert(arr12528C1.length == 1); -static assert(arr12528C2.length == 2 && arr12528C2[0] !is arr12528C2[1]); - /************************************************** 9745 Allow pointers to static variables **************************************************/ diff --git a/test/fail_compilation/test15989.d b/test/fail_compilation/test15989.d new file mode 100644 index 000000000000..29eab9c38cbd --- /dev/null +++ b/test/fail_compilation/test15989.d @@ -0,0 +1,52 @@ +/* +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test15989.d(40): Error: variable test15989.main.ctRegex : Unable to initialize enum with class or pointer to struct. Use static const variable instead. +fail_compilation/test15989.d(49): Error: variable test15989.test.c : Unable to initialize enum with class or pointer to struct. Use static const variable instead. +fail_compilation/test15989.d(50): Error: cannot use non-constant CTFE pointer in an initializer '&[3][0]' +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=15989 + +import core.stdc.stdio; + +interface Kickstart{ + bool foo( int ); +} + +class ShiftOr : Kickstart +{ + bool foo( int i ) + { + printf("i = %d\n", i); + return false; + } +} + +struct Regex +{ + Kickstart kickstart; +} + +Regex regex() +{ + return Regex(new ShiftOr()); +} + +void main() +{ + enum ctRegex = regex(); + Regex r = ctRegex; + r.kickstart.foo(7); +} + +class C { } + +void test() +{ + enum c = new C(); + enum pi = new int(3); +} +