109 changes: 78 additions & 31 deletions src/denum.d

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/doc.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module ddmd.doc;

import core.stdc.ctype;
import core.stdc.stdlib;
import core.stdc.stdio;
import core.stdc.string;
import core.stdc.time;
import ddmd.aggregate;
Expand Down Expand Up @@ -329,6 +330,8 @@ extern (C++) static Dsymbol getEponymousMember(TemplateDeclaration td)
return ad;
if (FuncDeclaration fd = td.onemember.isFuncDeclaration())
return fd;
if (auto em = td.onemember.isEnumMember())
return null; // Keep backward compatibility. See compilable/ddoc9.d
if (VarDeclaration vd = td.onemember.isVarDeclaration())
return td.constraint ? null : vd;
return null;
Expand Down
28 changes: 25 additions & 3 deletions src/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -6348,18 +6348,28 @@ public:
// Elide codegen because this is really speculative.
return false;
}

/* Even when this is reached to the codegen pass,
* a non-root nested template should not generate code,
* due to avoid ODR violation.
*/
if (enclosing && enclosing.inNonRoot())
{
if (tinst)
return tinst.needsCodegen();
{
auto r = tinst.needsCodegen();
minst = tinst.minst; // cache result
return r;
}
if (tnext)
return tnext.needsCodegen();
{
auto r = tnext.needsCodegen();
minst = tnext.minst; // cache result
return r;
}
return false;
}

/* The issue is that if the importee is compiled with a different -debug
* setting than the importer, the importer may believe it exists
* in the compiled importee when it does not, when the instantiation
Expand Down Expand Up @@ -7660,36 +7670,48 @@ extern (C++) void unSpeculative(Scope* sc, RootObject o)
extern (C++) bool definitelyValueParameter(Expression e)
{
// None of these can be value parameters
if (e.op == TOKtuple || e.op == TOKimport || e.op == TOKtype || e.op == TOKdottype || e.op == TOKtemplate || e.op == TOKdottd || e.op == TOKfunction || e.op == TOKerror || e.op == TOKthis || e.op == TOKsuper)
if (e.op == TOKtuple || e.op == TOKimport ||
e.op == TOKtype || e.op == TOKdottype ||
e.op == TOKtemplate || e.op == TOKdottd ||
e.op == TOKfunction || e.op == TOKerror ||
e.op == TOKthis || e.op == TOKsuper)
return false;

if (e.op != TOKdotvar)
return true;

/* Template instantiations involving a DotVar expression are difficult.
* In most cases, they should be treated as a value parameter, and interpreted.
* But they might also just be a fully qualified name, which should be treated
* as an alias.
*/

// x.y.f cannot be a value
FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration();
if (f)
return false;

while (e.op == TOKdotvar)
{
e = (cast(DotVarExp)e).e1;
}
// this.x.y and super.x.y couldn't possibly be valid values.
if (e.op == TOKthis || e.op == TOKsuper)
return false;

// e.type.x could be an alias
if (e.op == TOKdottype)
return false;

// var.x.y is the only other possible form of alias
if (e.op != TOKvar)
return true;

VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
// func.x.y is not an alias
if (!v)
return true;

// TODO: Should we force CTFE if it is a global constant?
return false;
}
Expand Down
11 changes: 6 additions & 5 deletions src/enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "root.h"
#include "dsymbol.h"
#include "declaration.h"
#include "tokens.h"

class Identifier;
Expand Down Expand Up @@ -70,25 +71,25 @@ class EnumDeclaration : public ScopeDsymbol
};


class EnumMember : public Dsymbol
class EnumMember : public VarDeclaration
{
public:
/* Can take the following forms:
* 1. id
* 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);
Expand Down
2 changes: 1 addition & 1 deletion src/iasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/json.d
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
140 changes: 94 additions & 46 deletions src/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -2695,6 +2695,69 @@ public:
*ps = null;
}

/***************************************
* Normalize `e` as the result of Type.resolve() process.
*/
final void resolveExp(Expression e, Type *pt, Expression *pe, Dsymbol* ps)
{
*pt = null;
*pe = null;
*ps = null;

Dsymbol s;
switch (e.op)
{
case TOKerror:
*pt = Type.terror;
return;

case TOKtype:
*pt = e.type;
return;

case TOKvar:
s = (cast(VarExp)e).var;
if (s.isVarDeclaration())
goto default;
//if (s.isOverDeclaration())
// todo;
break;

case TOKtemplate:
// TemplateDeclaration
s = (cast(TemplateExp)e).td;
break;

case TOKimport:
s = (cast(ScopeExp)e).sds;
// TemplateDeclaration, TemplateInstance, Import, Package, Module
break;

case TOKfunction:
s = getDsymbol(e);
break;

//case TOKthis:
//case TOKsuper:

//case TOKtuple:

//case TOKoverloadset:

//case TOKdotvar:
//case TOKdottd:
//case TOKdotti:
//case TOKdottype:
//case TOKdot:

default:
*pe = e;
return;
}

*ps = s;
}

/***************************************
* Return !=0 if the type or any of its subtypes is wild.
*/
Expand Down Expand Up @@ -6825,14 +6888,10 @@ public:
eindex = DsymbolExp.resolve(loc, sc, sindex, false);
Expression e = new IndexExp(loc, DsymbolExp.resolve(loc, sc, s, false), eindex);
e = e.semantic(sc);
if (e.op == TOKerror)
*pt = Type.terror;
else if (e.op == TOKtype)
*pt = (cast(TypeExp)e).type;
else
*pe = e;
resolveExp(e, pt, pe, ps);
return;
}

// Convert oindex to Expression, then try to resolve to constant.
if (tindex)
tindex.resolve(loc, sc, &eindex, &tindex, &sindex);
Expand Down Expand Up @@ -6866,6 +6925,8 @@ public:
*pe = isExpression(o);
if (*pt)
*pt = (*pt).semantic(loc, sc);
if (*pe)
resolveExp(*pe, pt, pe, ps);
}

final Expression toExpressionHelper(Expression e, size_t i = 0)
Expand Down Expand Up @@ -6956,12 +7017,7 @@ public:

ex = toExpressionHelper(ex, i + 1);
ex = ex.semantic(sc);
if (ex.op == TOKerror)
*pt = Type.terror;
else if (ex.op == TOKtype)
*pt = ex.type;
else if ((*ps = getDsymbol(ex)) is null)
*pe = ex;
resolveExp(ex, pt, pe, ps);
return;
}
Type t = s.getType(); // type symbol, type alias, or type tuple?
Expand Down Expand Up @@ -7019,12 +7075,7 @@ public:

e = toExpressionHelper(e, i);
e = e.semantic(sc);
if (e.op == TOKerror)
*pt = Type.terror;
else if (e.op == TOKtype)
*pt = e.type;
else if ((*ps = getDsymbol(e)) is null)
*pe = e;
resolveExp(e, pt, pe, ps);
return;
}
else
Expand All @@ -7050,6 +7101,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
Expand Down Expand Up @@ -7088,12 +7146,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)
Expand Down Expand Up @@ -7265,6 +7317,8 @@ public:
resolve(loc, sc, &e, &t, &s);
if (t && t.ty != Tident)
s = t.toDsymbol(sc);
if (e)
s = getDsymbol(e);
return s;
}

Expand Down Expand Up @@ -7528,12 +7582,7 @@ public:
{
auto e = toExpressionHelper(new TypeExp(loc, t));
e = e.semantic(sc);
if (e.op == TOKerror)
goto Lerr;
else if (e.op == TOKtype)
*pt = e.type;
else if ((*ps = getDsymbol(e)) is null)
*pe = e;
resolveExp(e, pt, pe, ps);
}
}
if (*pt)
Expand Down Expand Up @@ -7638,12 +7687,7 @@ public:
{
auto e = toExpressionHelper(new TypeExp(loc, t));
e = e.semantic(sc);
if (e.op == TOKerror)
goto Lerr;
else if (e.op == TOKtype)
*pt = e.type;
else if ((*ps = getDsymbol(e)) is null)
*pe = e;
resolveExp(e, pt, pe, ps);
}
}
if (*pt)
Expand Down Expand Up @@ -7834,6 +7878,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))
{
Expand All @@ -7860,11 +7910,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)
{
Expand Down Expand Up @@ -8690,6 +8736,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))
{
Expand All @@ -8716,11 +8768,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)
{
Expand Down
4 changes: 2 additions & 2 deletions src/tocvdebug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/visitor.d
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ public:

void visit(EnumMember s)
{
visit(cast(Dsymbol)s);
visit(cast(VarDeclaration)s);
}

void visit(Import s)
Expand Down
2 changes: 1 addition & 1 deletion src/visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down
5 changes: 5 additions & 0 deletions test/compilable/ddoc9.d
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ struct Struct(T) { }
/// Union Documentation
union Union(T) { }

/// Template documentation with anonymous enum
template TemplateWithAnonEnum(T)
{
enum { TemplateWithAnonEnum = 1 }
}
4 changes: 4 additions & 0 deletions test/compilable/extra-files/ddoc9.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ <h1>ddoc9</h1>
</big></dt>
<dd><u>Union</u> Documentation<br><br>

</dd>
<dt><big><a name="TemplateWithAnonEnum"></a>template <u>TemplateWithAnonEnum</u>(T)</big></dt>
<dd>Template documentation with anonymous enum<br><br>

</dd>
</dl>

Expand Down
6 changes: 6 additions & 0 deletions test/compilable/imports/test15150a.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module imports.test15150a;

enum
{
x
}
3 changes: 3 additions & 0 deletions test/compilable/imports/test15150b.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module imports.test15150b;

import imports.test15150a : x;
8 changes: 8 additions & 0 deletions test/compilable/test15150.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// PERMUTE_ARGS:

module test15150;

import imports.test15150a;
import imports.test15150b;

enum y = x;
4 changes: 2 additions & 2 deletions test/fail_compilation/fail10528.d
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions test/runnable/ice15138.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// EXTRA_SOURCES: imports/ice15138a.d
// PERMUTE_ARGS: -unittest -inline
// COMPILE_SEPARATELY

import imports.ice15138a;

void main()
{
JSONValue v;
v.get!JSONValue;
}
28 changes: 28 additions & 0 deletions test/runnable/imports/ice15138a.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module imports.ice15138a;

alias AliasSeq(TL...) = TL;

alias FieldNameTuple(T...) = AliasSeq!();

struct TaggedAlgebraic(U)
{
alias X = FieldNameTuple!(U.tupleof);
}

void get(T, U)(TaggedAlgebraic!U ta) {}

union PayloadUnion
{
int dummy;
}

struct JSONValue
{
alias Payload = TaggedAlgebraic!PayloadUnion;

void get(T)()
{
Payload payload;
.get!T(payload);
}
}
16 changes: 16 additions & 0 deletions test/runnable/template9.d
Original file line number Diff line number Diff line change
Expand Up @@ -4711,6 +4711,22 @@ void test15116()
assert(func(12, "") == 2);
}

/******************************************/
// 15152

void test15152()
{
void func(string M)() { }

struct S
{
enum name = "a";
}

enum s = S.init;
func!(s.name);
}

/******************************************/

int main()
Expand Down