Skip to content

Commit

Permalink
Merge pull request #6164 from WalterBright/fix15989
Browse files Browse the repository at this point in the history
fix Issue 15989 - Initializing manifest constants with CTFE allocated…
  • Loading branch information
andralex committed Oct 2, 2016
2 parents 0735a4c + e6c2080 commit 39e4faf
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 30 deletions.
55 changes: 30 additions & 25 deletions src/declaration.d
Expand Up @@ -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())
Expand Down
5 changes: 0 additions & 5 deletions test/compilable/interpret3.d
Expand Up @@ -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
**************************************************/
Expand Down
52 changes: 52 additions & 0 deletions 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);
}

0 comments on commit 39e4faf

Please sign in to comment.