Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/dcast.d
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -3866,13 +3866,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 @@ -8200,13 +8197,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 @@ -9903,7 +9897,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 @@ -9986,6 +9980,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 @@ -10054,14 +10088,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 @@ -4386,6 +4392,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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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(){}
Loading