Skip to content

Commit

Permalink
Merge pull request #5202 from 9rnsr/fix14965
Browse files Browse the repository at this point in the history
[REG2.031] Issue 14965 - Forward reference to inferred return type of function call when using auto return type
  • Loading branch information
MartinNowak committed Mar 7, 2016
2 parents d9e32d0 + 4b6779d commit 624ad66
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 41 deletions.
27 changes: 27 additions & 0 deletions src/dcast.d
Expand Up @@ -1913,6 +1913,15 @@ extern (C++) Expression castTo(Expression e, Scope* sc, Type t)
}
}

if (auto f = isFuncAddress(e))
{
if (f.checkForwardRef(e.loc))
{
result = new ErrorExp();
return;
}
}

visit(cast(Expression)e);
}

Expand Down Expand Up @@ -2134,6 +2143,15 @@ extern (C++) Expression castTo(Expression e, Scope* sc, Type t)
}
}

if (auto f = isFuncAddress(e))
{
if (f.checkForwardRef(e.loc))
{
result = new ErrorExp();
return;
}
}

visit(cast(Expression)e);
}

Expand Down Expand Up @@ -2180,6 +2198,15 @@ extern (C++) Expression castTo(Expression e, Scope* sc, Type t)
}
}

if (auto f = isFuncAddress(e))
{
if (f.checkForwardRef(e.loc))
{
result = new ErrorExp();
return;
}
}

visit(cast(Expression)e);
}

Expand Down
73 changes: 54 additions & 19 deletions src/expression.d
Expand Up @@ -3887,13 +3887,10 @@ public:
if (!f.functionSemantic())
return new ErrorExp();

if (!f.type.deco)
{
const(char)* trailMsg = f.inferRetType ? "inferred return type of function call " : "";
.error(loc, "forward reference to %s'%s'", trailMsg, f.toChars());
if (!hasOverloads && f.checkForwardRef(loc))
return new ErrorExp();
}
FuncDeclaration fd = s.isFuncDeclaration();

auto fd = s.isFuncDeclaration();
fd.type = f.type;
return new VarExp(loc, fd, hasOverloads);
}
Expand Down Expand Up @@ -8222,13 +8219,10 @@ public:
L1:
{
assert(ds);
if (FuncDeclaration f = ds.isFuncDeclaration())
if (auto f = ds.isFuncDeclaration())
{
if (!f.type.deco)
{
error("forward reference to %s", f.toChars());
if (f.checkForwardRef(loc))
return new ErrorExp();
}
}
const(char)* s = mangle(ds);
Expression e = new StringExp(loc, cast(void*)s, strlen(s));
Expand Down Expand Up @@ -9931,7 +9925,7 @@ public:
if (!type)
{
e1 = e1org; // Bugzilla 10922, avoid recursive expression printing
error("forward reference to inferred return type of function call %s", toChars());
error("forward reference to inferred return type of function call '%s'", toChars());
return new ErrorExp();
}
if (f && f.tintro)
Expand Down Expand Up @@ -10014,6 +10008,46 @@ public:
}
}

FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null)
{
if (e.op == TOKaddress)
{
auto ae1 = (cast(AddrExp)e).e1;
if (ae1.op == TOKvar)
{
auto ve = cast(VarExp)ae1;
if (hasOverloads)
*hasOverloads = ve.hasOverloads;
return ve.var.isFuncDeclaration();
}
if (ae1.op == TOKdotvar)
{
auto dve = cast(DotVarExp)ae1;
if (hasOverloads)
*hasOverloads = dve.hasOverloads;
return dve.var.isFuncDeclaration();
}
}
else
{
if (e.op == TOKsymoff)
{
auto soe = cast(SymOffExp)e;
if (hasOverloads)
*hasOverloads = soe.hasOverloads;
return soe.var.isFuncDeclaration();
}
if (e.op == TOKdelegate)
{
auto dge = cast(DelegateExp)e;
if (hasOverloads)
*hasOverloads = dge.hasOverloads;
return dge.func.isFuncDeclaration();
}
}
return null;
}

/***********************************************************
*/
extern (C++) final class AddrExp : UnaExp
Expand Down Expand Up @@ -10082,14 +10116,15 @@ public:
error("cannot take address of %s", e1.toChars());
return new ErrorExp();
}
if (!e1.type.deco)

bool hasOverloads;
if (auto f = isFuncAddress(this, &hasOverloads))
{
if (!hasOverloads && f.checkForwardRef(loc))
return new ErrorExp();
}
else if (!e1.type.deco)
{
/* No deco means semantic() was not run on the type.
* We have to run semantic() on the symbol to get the right type:
* auto x = &bar;
* pure: int bar() { return 1;}
* otherwise the 'pure' is missing from the type assigned to x.
*/
if (e1.op == TOKvar)
{
VarExp ve = cast(VarExp)e1;
Expand Down
23 changes: 23 additions & 0 deletions src/func.d
Expand Up @@ -2321,6 +2321,29 @@ public:
return !errors && !semantic3Errors;
}

/****************************************************
* Check that this function type is properly resolved.
* If not, report "forward reference error" and return true.
*/
final bool checkForwardRef(Loc loc)
{
if (!functionSemantic())
return true;

/* No deco means the functionSemantic() call could not resolve
* forward referenes in the type of this function.
*/
if (!type.deco)
{
bool inSemantic3 = (inferRetType && semanticRun >= PASSsemantic3);
.error(loc, "forward reference to %s'%s'",
(inSemantic3 ? "inferred return type of function " : "").ptr,
toChars());
return true;
}
return false;
}

// called from semantic3
final VarDeclaration declareThis(Scope* sc, AggregateDeclaration ad)
{
Expand Down
16 changes: 5 additions & 11 deletions src/init.d
Expand Up @@ -785,20 +785,14 @@ public:
se.error("cannot infer type from %s %s", se.sds.kind(), se.toChars());
return new ErrorInitializer();
}

// Give error for overloaded function addresses
if (exp.op == TOKsymoff)
bool hasOverloads;
if (auto f = isFuncAddress(exp, &hasOverloads))
{
SymOffExp se = cast(SymOffExp)exp;
if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
{
exp.error("cannot infer type from overloaded function symbol %s", exp.toChars());
if (f.checkForwardRef(loc))
return new ErrorInitializer();
}
}
if (exp.op == TOKdelegate)
{
DelegateExp se = cast(DelegateExp)exp;
if (se.hasOverloads && se.func.isFuncDeclaration() && !se.func.isFuncDeclaration().isUnique())
if (hasOverloads && !f.isUnique())
{
exp.error("cannot infer type from overloaded function symbol %s", exp.toChars());
return new ErrorInitializer();
Expand Down
11 changes: 11 additions & 0 deletions src/mtype.d
Expand Up @@ -7549,6 +7549,17 @@ public:
* template functions.
*/
}
if (auto f = exp.op == TOKvar ? (cast( VarExp)exp).var.isFuncDeclaration()
: exp.op == TOKdotvar ? (cast(DotVarExp)exp).var.isFuncDeclaration() : null)
{
if (f.checkForwardRef(loc))
goto Lerr;
}
if (auto f = isFuncAddress(exp))
{
if (f.checkForwardRef(loc))
goto Lerr;
}

Type t = exp.type;
if (!t)
Expand Down
11 changes: 11 additions & 0 deletions src/statement.d
Expand Up @@ -1150,7 +1150,13 @@ public:
exp = exp.addDtorHook(sc);
if (checkNonAssignmentArrayOp(exp))
exp = new ErrorExp();
if (auto f = isFuncAddress(exp))
{
if (f.checkForwardRef(exp.loc))
exp = new ErrorExp();
}
discardValue(exp);

exp = exp.optimize(WANTvalue);
exp = checkGC(sc, exp);
if (exp.op == TOKerror)
Expand Down Expand Up @@ -4382,6 +4388,11 @@ public:
exp = resolveProperties(sc, exp);
if (exp.checkType())
exp = new ErrorExp();
if (auto f = isFuncAddress(exp))
{
if (fd.inferRetType && f.checkForwardRef(exp.loc))
exp = new ErrorExp();
}
if (checkNonAssignmentArrayOp(exp))
exp = new ErrorExp();

Expand Down
2 changes: 1 addition & 1 deletion test/fail_compilation/diag7747.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/diag7747.d(8): Error: forward reference to inferred return type of function call 'fact'
fail_compilation/diag7747.d(8): Error: forward reference to inferred return type of function call 'fact(n - 1)'
---
*/

Expand Down
6 changes: 3 additions & 3 deletions test/fail_compilation/fail12236.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail12236.d(16): Error: forward reference to inferred return type of function call 'f1'
fail_compilation/fail12236.d(16): Error: forward reference to inferred return type of function 'f1'
fail_compilation/fail12236.d(16): while evaluating pragma(msg, f1.mangleof)
fail_compilation/fail12236.d(21): Error: forward reference to f2
fail_compilation/fail12236.d(21): Error: forward reference to inferred return type of function 'f2'
fail_compilation/fail12236.d(21): while evaluating pragma(msg, f2(T)(T).mangleof)
fail_compilation/fail12236.d(27): Error: template instance fail12236.f2!int error instantiating
fail_compilation/fail12236.d(31): Error: forward reference to __lambda1
fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function '__lambda1'
fail_compilation/fail12236.d(31): while evaluating pragma(msg, __lambda1.mangleof)
---
*/
Expand Down
38 changes: 38 additions & 0 deletions test/fail_compilation/fail14965.d
@@ -0,0 +1,38 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail14965.d(19): Error: forward reference to inferred return type of function 'foo1'
fail_compilation/fail14965.d(20): Error: forward reference to inferred return type of function 'foo2'
fail_compilation/fail14965.d(22): Error: forward reference to inferred return type of function 'bar1'
fail_compilation/fail14965.d(23): Error: forward reference to inferred return type of function 'bar2'
fail_compilation/fail14965.d(25): Error: forward reference to inferred return type of function 'baz1'
fail_compilation/fail14965.d(26): Error: forward reference to inferred return type of function 'baz2'
fail_compilation/fail14965.d(30): Error: forward reference to inferred return type of function 'foo1'
fail_compilation/fail14965.d(31): Error: forward reference to inferred return type of function 'foo2'
fail_compilation/fail14965.d(33): Error: forward reference to inferred return type of function 'bar1'
fail_compilation/fail14965.d(34): Error: forward reference to inferred return type of function 'bar2'
fail_compilation/fail14965.d(36): Error: forward reference to inferred return type of function 'baz1'
fail_compilation/fail14965.d(37): Error: forward reference to inferred return type of function 'baz2'
---
*/

auto foo1() { alias F = typeof(foo1); } // TypeTypeof
auto foo2() { alias FP = typeof(&foo2); } // TypeTypeof

auto bar1() { auto fp = &bar1; } // ExpInitializer
auto bar2() { auto fp = cast(void function())&bar2; } // castTo

auto baz1() { return &baz1; } // ReturnStatement
auto baz2() { (&baz2); } // ExpStatement

class C
{
auto foo1() { alias F = typeof(this.foo1); }
auto foo2() { alias FP = typeof(&this.foo2); }

auto bar1() { auto fp = &this.bar1; }
auto bar2() { auto dg = cast(void delegate())&this.bar2; }

auto baz1() { return &baz1; }
auto baz2() { (&baz2); }
}
4 changes: 2 additions & 2 deletions test/fail_compilation/ice12235.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice12235.d(14): Error: forward reference to __lambda1
fail_compilation/ice12235.d(15): Error: forward reference to __lambda1
fail_compilation/ice12235.d(14): Error: forward reference to inferred return type of function '__lambda1'
fail_compilation/ice12235.d(15): Error: forward reference to inferred return type of function '__lambda1'
fail_compilation/ice12235.d(15): while evaluating pragma(msg, __lambda1.mangleof)
---
*/
Expand Down
6 changes: 4 additions & 2 deletions test/fail_compilation/test9176.d
@@ -1,15 +1,17 @@
/*
TEST_OUTPUT:
---
fail_compilation/test9176.d(12): Error: forward reference to inferred return type of function call 'get'
fail_compilation/test9176.d(13): Error: forward reference to inferred return type of function call 'get()'
---
*/

void foo(int x) {}
static assert(!is(typeof(foo(S()))));

struct S {
struct S
{
auto get() { return get(); }
alias get this;
}

void main(){}

0 comments on commit 624ad66

Please sign in to comment.