Skip to content

Commit

Permalink
Merge pull request #5163 from 9rnsr/fix15152
Browse files Browse the repository at this point in the history
[REG2.069.0-devel] Issue 15152 - template fails to instantiate if argument is itself a template
  • Loading branch information
MartinNowak committed Oct 6, 2015
2 parents e13c2bc + 4d1b086 commit 8830d97
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 31 deletions.
14 changes: 13 additions & 1 deletion src/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -7674,36 +7674,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
101 changes: 71 additions & 30 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 Down Expand Up @@ -7528,12 +7579,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 +7684,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
16 changes: 16 additions & 0 deletions test/runnable/template9.d
Original file line number Diff line number Diff line change
Expand Up @@ -4691,6 +4691,22 @@ void test14886()
static assert(is(typeof(bar2(R.init, x)) == int));
}

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

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

struct S
{
enum name = "a";
}

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

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

int main()
Expand Down

0 comments on commit 8830d97

Please sign in to comment.