diff --git a/src/declaration.d b/src/declaration.d index eb378631baf5..89571fed1d47 100644 --- a/src/declaration.d +++ b/src/declaration.d @@ -1898,7 +1898,7 @@ public: sem = Semantic2Done; } - override final const(char)* kind() + override const(char)* kind() { return "variable"; } diff --git a/src/denum.d b/src/denum.d index 251aa7770062..fa6797a30fe8 100644 --- a/src/denum.d +++ b/src/denum.d @@ -8,6 +8,7 @@ module ddmd.denum; +import core.stdc.stdio; import ddmd.access; import ddmd.backend; import ddmd.declaration; @@ -97,7 +98,7 @@ public: EnumMember em = (*members)[i].isEnumMember(); em.ed = this; //printf("add %s to scope %s\n", em->toChars(), scopesym->toChars()); - em.addMember(sc, scopesym); + em.addMember(sc, isAnonymous() ? scopesym : this); } } added = true; @@ -499,7 +500,7 @@ public: /*********************************************************** */ -extern (C++) final class EnumMember : Dsymbol +extern (C++) final class EnumMember : VarDeclaration { public: /* Can take the following forms: @@ -507,31 +508,28 @@ public: * 2. id = value * 3. type id = value */ - Expression value; + @property ref value() { return (cast(ExpInitializer)_init).exp; } // A cast() is injected to 'value' after semantic(), // but 'origValue' will preserve the original value, // or previous value + 1 if none was specified. Expression origValue; - Type type; + Type origType; EnumDeclaration ed; - VarDeclaration vd; - extern (D) this(Loc loc, Identifier id, Expression value, Type type) + extern (D) this(Loc loc, Identifier id, Expression value, Type origType) { - super(id); - this.value = value; + super(loc, null, id ? id : Id.empty, new ExpInitializer(loc, value)); this.origValue = value; - this.type = type; - this.loc = loc; + this.origType = origType; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); - return new EnumMember(loc, ident, value ? value.syntaxCopy() : null, type ? type.syntaxCopy() : null); + return new EnumMember(loc, ident, value ? value.syntaxCopy() : null, origType ? origType.syntaxCopy() : null); } override const(char)* kind() @@ -559,16 +557,22 @@ public: if (errors || semanticRun >= PASSsemanticdone) return; - semanticRun = PASSsemantic; if (_scope) sc = _scope; + protection = ed.isAnonymous() ? ed.protection : Prot(PROTpublic); + storage_class = STCmanifest; + userAttribDecl = ed.isAnonymous() ? ed.userAttribDecl : null; + + semanticRun = PASSsemantic; + // The first enum member is special bool first = (this == (*ed.members)[0]); - if (type) + if (origType) { - type = type.semantic(loc, sc); + origType = origType.semantic(loc, sc); + type = origType; assert(value); // "type id;" is not a valid enum member declaration } @@ -598,10 +602,10 @@ public: for (size_t i = 0; i < ed.members.dim; i++) { EnumMember em = (*ed.members)[i].isEnumMember(); - if (!em || em == this || em.semanticRun < PASSsemanticdone || em.type) + if (!em || em == this || em.semanticRun < PASSsemanticdone || em.origType) continue; - //printf("[%d] em = %s, em->semanticRun = %d\n", i, toChars(), em->semanticRun); + //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); Expression ev = em.value; ev = ev.implicitCastTo(sc, ed.memtype); ev = ev.ctfeInterpret(); @@ -618,7 +622,7 @@ public: } } - if (ed.memtype && !type) + if (ed.memtype && !origType) { e = e.implicitCastTo(sc, ed.memtype); e = e.ctfeInterpret(); @@ -629,9 +633,9 @@ public: if (!ed.isAnonymous()) e = e.castTo(sc, ed.type); } - else if (type) + else if (origType) { - e = e.implicitCastTo(sc, type); + e = e.implicitCastTo(sc, origType); e = e.ctfeInterpret(); assert(ed.isAnonymous()); @@ -703,6 +707,7 @@ public: emprev.ed.toChars(), emprev.toChars(), ed.memtype.toChars()); goto Lerrors; } + // Now set e to (eprev + 1) e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type.tint32)); e = e.semantic(sc); @@ -734,6 +739,8 @@ public: } value = e; } + if (!origType) + type = value.type; assert(origValue); semanticRun = PASSsemanticdone; @@ -744,20 +751,7 @@ public: semantic(sc); if (errors) return new ErrorExp(); - if (!vd) - { - assert(value); - vd = new VarDeclaration(loc, type, ident, new ExpInitializer(loc, value.copy())); - - vd.storage_class = STCmanifest; - vd.semantic(sc); - - vd.protection = ed.isAnonymous() ? ed.protection : Prot(PROTpublic); - vd.parent = ed.isAnonymous() ? ed.parent : ed; - vd.userAttribDecl = ed.isAnonymous() ? ed.userAttribDecl : null; - } - checkAccess(loc, sc, null, vd); - Expression e = new VarExp(loc, vd); + Expression e = new VarExp(loc, this); return e.semantic(sc); } diff --git a/src/enum.h b/src/enum.h index 3abb79e47ac1..3cfa200d181f 100644 --- a/src/enum.h +++ b/src/enum.h @@ -18,6 +18,7 @@ #include "root.h" #include "dsymbol.h" +#include "declaration.h" #include "tokens.h" class Identifier; @@ -70,7 +71,7 @@ class EnumDeclaration : public ScopeDsymbol }; -class EnumMember : public Dsymbol +class EnumMember : public VarDeclaration { public: /* Can take the following forms: @@ -78,17 +79,17 @@ class EnumMember : public Dsymbol * 2. id = value * 3. type id = value */ - Expression *value; + Expression *&value(); + // A cast() is injected to 'value' after semantic(), // but 'origValue' will preserve the original value, // or previous value + 1 if none was specified. Expression *origValue; - Type *type; + Type *origType; EnumDeclaration *ed; - VarDeclaration *vd; - EnumMember(Loc loc, Identifier *id, Expression *value, Type *type); + EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType); Dsymbol *syntaxCopy(Dsymbol *s); const char *kind(); void semantic(Scope *sc); diff --git a/src/iasm.c b/src/iasm.c index 0eb3e3a344b5..ea037e3faf2d 100644 --- a/src/iasm.c +++ b/src/iasm.c @@ -2335,7 +2335,7 @@ static void asm_merge_symbol(OPND *o1, Dsymbol *s) em = s->isEnumMember(); if (em) { - o1->disp = em->value->toInteger(); + o1->disp = em->value()->toInteger(); return; } o1->s = s; // a C identifier diff --git a/src/json.d b/src/json.d index 6d403853486b..123fb85c782b 100644 --- a/src/json.d +++ b/src/json.d @@ -745,8 +745,8 @@ public: override void visit(EnumMember s) { objectStart(); - jsonProperties(s); - property("type", "deco", s.type); + jsonProperties(cast(Dsymbol)s); + property("type", "deco", s.origType); objectEnd(); } diff --git a/src/mtype.d b/src/mtype.d index 6644dffdbaff..029ba099b617 100644 --- a/src/mtype.d +++ b/src/mtype.d @@ -7050,6 +7050,13 @@ public: L2: s = sm.toAlias(); } + + if (auto em = s.isEnumMember()) + { + // It's not a type, it's an expression + *pe = em.getVarExp(loc, sc); + return; + } if (VarDeclaration v = s.isVarDeclaration()) { /* This is mostly same with DsymbolExp::semantic(), but we cannot use it @@ -7088,12 +7095,6 @@ public: return; } } - if (EnumMember em = s.isEnumMember()) - { - // It's not a type, it's an expression - *pe = em.getVarExp(loc, sc); - return; - } L1: Type t = s.getType(); if (!t) @@ -7265,6 +7266,8 @@ public: resolve(loc, sc, &e, &t, &s); if (t && t.ty != Tident) s = t.toDsymbol(sc); + if (e) + s = getDsymbol(e); return s; } @@ -7834,6 +7837,12 @@ public: if (!s.isFuncDeclaration()) // because of overloading s.checkDeprecated(e.loc, sc); s = s.toAlias(); + + if (auto em = s.isEnumMember()) + { + return em.getVarExp(e.loc, sc); + } + VarDeclaration v = s.isVarDeclaration(); if (v && (!v.type || !v.type.deco)) { @@ -7860,11 +7869,7 @@ public: { return new TypeExp(e.loc, s.getType()); } - EnumMember em = s.isEnumMember(); - if (em) - { - return em.getVarExp(e.loc, sc); - } + TemplateMixin tm = s.isTemplateMixin(); if (tm) { @@ -8690,6 +8695,12 @@ public: if (!s.isFuncDeclaration()) // because of overloading s.checkDeprecated(e.loc, sc); s = s.toAlias(); + + if (auto em = s.isEnumMember()) + { + return em.getVarExp(e.loc, sc); + } + VarDeclaration v = s.isVarDeclaration(); if (v && (!v.type || !v.type.deco)) { @@ -8716,11 +8727,7 @@ public: { return new TypeExp(e.loc, s.getType()); } - EnumMember em = s.isEnumMember(); - if (em) - { - return em.getVarExp(e.loc, sc); - } + TemplateMixin tm = s.isTemplateMixin(); if (tm) { diff --git a/src/tocvdebug.c b/src/tocvdebug.c index 859ef02aaba9..622b7c0f1e0b 100644 --- a/src/tocvdebug.c +++ b/src/tocvdebug.c @@ -159,7 +159,7 @@ unsigned cv4_Denum(EnumDeclaration *e) { EnumMember *sf = (*e->members)[i]->isEnumMember(); if (sf) { - dinteger_t value = sf->value->toInteger(); + dinteger_t value = sf->value()->toInteger(); unsigned fnamelen1 = fnamelen; // store only member's simple name @@ -233,7 +233,7 @@ unsigned cv4_Denum(EnumDeclaration *e) if (fieldi > nfields) break; // chop off the rest - dinteger_t value = sf->value->toInteger(); + dinteger_t value = sf->value()->toInteger(); TOWORD(dt->data + j,(config.fulltypes == CV8) ? LF_ENUMERATE_V3 : LF_ENUMERATE); unsigned attribute = 0; TOWORD(dt->data + j + 2,attribute); diff --git a/src/visitor.d b/src/visitor.d index b0649f64dab8..7817a7928bd3 100644 --- a/src/visitor.d +++ b/src/visitor.d @@ -380,7 +380,7 @@ public: void visit(EnumMember s) { - visit(cast(Dsymbol)s); + visit(cast(VarDeclaration)s); } void visit(Import s) diff --git a/src/visitor.h b/src/visitor.h index 9f425fc9872a..4658ede069b6 100644 --- a/src/visitor.h +++ b/src/visitor.h @@ -371,7 +371,7 @@ class Visitor virtual void visit(StaticAssert *s) { visit((Dsymbol *)s); } virtual void visit(DebugSymbol *s) { visit((Dsymbol *)s); } virtual void visit(VersionSymbol *s) { visit((Dsymbol *)s); } - virtual void visit(EnumMember *s) { visit((Dsymbol *)s); } + virtual void visit(EnumMember *s) { visit((VarDeclaration *)s); } virtual void visit(Import *s) { visit((Dsymbol *)s); } virtual void visit(OverloadSet *s) { visit((Dsymbol *)s); } virtual void visit(LabelDsymbol *s) { visit((Dsymbol *)s); } diff --git a/test/compilable/imports/test15150a.d b/test/compilable/imports/test15150a.d new file mode 100644 index 000000000000..fe3b8ab06bea --- /dev/null +++ b/test/compilable/imports/test15150a.d @@ -0,0 +1,6 @@ +module imports.test15150a; + +enum +{ + x +} diff --git a/test/compilable/imports/test15150b.d b/test/compilable/imports/test15150b.d new file mode 100644 index 000000000000..24b0928cc793 --- /dev/null +++ b/test/compilable/imports/test15150b.d @@ -0,0 +1,3 @@ +module imports.test15150b; + +import imports.test15150a : x; diff --git a/test/compilable/test15150.d b/test/compilable/test15150.d new file mode 100644 index 000000000000..3a00b80348be --- /dev/null +++ b/test/compilable/test15150.d @@ -0,0 +1,8 @@ +// PERMUTE_ARGS: + +module test15150; + +import imports.test15150a; +import imports.test15150b; + +enum y = x; diff --git a/test/fail_compilation/fail10528.d b/test/fail_compilation/fail10528.d index a1ebedeabb49..80199e2c438c 100644 --- a/test/fail_compilation/fail10528.d +++ b/test/fail_compilation/fail10528.d @@ -3,8 +3,8 @@ TEST_OUTPUT: --- fail_compilation/fail10528.d(19): Error: module fail10528 variable a10528.a is private fail_compilation/fail10528.d(20): Error: variable a10528.a is not accessible from module fail10528 -fail_compilation/fail10528.d(22): Error: variable a10528.b is not accessible from module fail10528 -fail_compilation/fail10528.d(23): Error: variable a10528.b is not accessible from module fail10528 +fail_compilation/fail10528.d(22): Error: module fail10528 enum member a10528.b is private +fail_compilation/fail10528.d(23): Error: enum member a10528.b is not accessible from module fail10528 fail_compilation/fail10528.d(25): Error: variable a10528.S.c is not accessible from module fail10528 fail_compilation/fail10528.d(26): Error: variable a10528.S.c is not accessible from module fail10528 fail_compilation/fail10528.d(28): Error: variable a10528.C.d is not accessible from module fail10528