From 4b6779d2ff0b95866205189cb55e5aef00c13c7e Mon Sep 17 00:00:00 2001 From: k-hara Date: Mon, 19 Oct 2015 11:52:44 +0900 Subject: [PATCH] fix Issue 14965 - Forward reference to inferred return type of function call when using auto return type If a function symbol is used, its overload resolution should be deferred until: ```d func(...) // CallExp.semantic func.mangleof // DotIdExp.semanticY typeof(func) // TypeTypeof.resolve typeof(&func) // TypeTypeof.resolve auto v = &func; // ExpInitializer.inferType &func; // ExpStatement.semantic return &func; // ReturnStatement ``` When the semantic analysis reaches to them, the function forward reference can beome actual error. Other use of 'func' should be treated as a property-like function call (done in `resolveProperties`) and finally handled in `CallExp`. --- src/dcast.d | 27 ++++++++++ src/expression.d | 73 ++++++++++++++++++++------- src/func.d | 23 +++++++++ src/init.d | 16 ++---- src/mtype.d | 11 ++++ src/statement.d | 11 ++++ test/fail_compilation/diag7747.d | 2 +- test/fail_compilation/fail12236.d | 6 +-- test/fail_compilation/fail14965.d | 38 ++++++++++++++ test/fail_compilation/ice12235.d | 4 +- test/fail_compilation/test9176.d | 6 ++- test/runnable/overload.d | 83 +++++++++++++++++++++++++++++-- 12 files changed, 259 insertions(+), 41 deletions(-) create mode 100644 test/fail_compilation/fail14965.d diff --git a/src/dcast.d b/src/dcast.d index ca0fda500bbb..f6d9a4231f06 100644 --- a/src/dcast.d +++ b/src/dcast.d @@ -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); } @@ -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); } @@ -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); } diff --git a/src/expression.d b/src/expression.d index eb1a5d127c11..9a56aeb42ba0 100644 --- a/src/expression.d +++ b/src/expression.d @@ -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); } @@ -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)); @@ -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) @@ -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 @@ -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; diff --git a/src/func.d b/src/func.d index 313c82d97df6..c8e74ef12ca4 100644 --- a/src/func.d +++ b/src/func.d @@ -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) { diff --git a/src/init.d b/src/init.d index 25ad4f50a5df..4792cf2bd06c 100644 --- a/src/init.d +++ b/src/init.d @@ -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(); diff --git a/src/mtype.d b/src/mtype.d index 63586262b08f..e8f35651b231 100644 --- a/src/mtype.d +++ b/src/mtype.d @@ -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) diff --git a/src/statement.d b/src/statement.d index 52f4cdbac32d..500e7ba5876d 100644 --- a/src/statement.d +++ b/src/statement.d @@ -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) @@ -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(); diff --git a/test/fail_compilation/diag7747.d b/test/fail_compilation/diag7747.d index d13b1256d508..0756911cab39 100644 --- a/test/fail_compilation/diag7747.d +++ b/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)' --- */ diff --git a/test/fail_compilation/fail12236.d b/test/fail_compilation/fail12236.d index 1482a3a6d637..ea950667976a 100644 --- a/test/fail_compilation/fail12236.d +++ b/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) --- */ diff --git a/test/fail_compilation/fail14965.d b/test/fail_compilation/fail14965.d new file mode 100644 index 000000000000..f1a1ec152e15 --- /dev/null +++ b/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); } +} diff --git a/test/fail_compilation/ice12235.d b/test/fail_compilation/ice12235.d index e18bf047315e..1bf55b90ac3a 100644 --- a/test/fail_compilation/ice12235.d +++ b/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) --- */ diff --git a/test/fail_compilation/test9176.d b/test/fail_compilation/test9176.d index 74931f382de3..4cdea88ddff1 100644 --- a/test/fail_compilation/test9176.d +++ b/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(){} diff --git a/test/runnable/overload.d b/test/runnable/overload.d index 3a2809f6fef5..f8fa7d5cdda2 100644 --- a/test/runnable/overload.d +++ b/test/runnable/overload.d @@ -664,9 +664,9 @@ template Foo1900(T) { } } -mixin Foo1900!(int) A; -mixin Foo1900!(char) B; -alias Bar1900!(int) bar; //error +mixin Foo1900!(int) A1900; +mixin Foo1900!(char) B1900; +alias Bar1900!(int) bar1900; // error /***************************************************/ // 7780 @@ -1135,6 +1135,82 @@ void test14989() static assert(B14989!string == 3); // OK <- error } +/***************************************************/ +// 14965 + +auto f14965a1() { return f14965a1(123); } +int f14965a1(int x) { return x; } + +int f14965a2(int x) { return x; } +auto f14965a2() { return f14965a2(123); } + +auto f14965b1() { int function(int) fp = &f14965b1; return fp(123); } +int f14965b1(int x) { return x; } + +int f14965b2(int x) { return x; } +auto f14965b2() { int function(int) fp = &f14965b2; return fp(123); } + +auto f14965c1() { auto fp = cast(int function(int))&f14965c1; return fp(123); } +int f14965c1(int x) { return x; } + +int f14965c2(int x) { return x; } +auto f14965c2() { auto fp = cast(int function(int))&f14965c2; return fp(123); } + +int function(int) f14965d1() { return &f14965d1; } +int f14965d1(int n) { return 10 + n; } + +int f14965d2(int n) { return 10 + n; } +int function(int) f14965d2() { return &f14965d2; } + +class C +{ + auto fa1() { return this.fa1(123); } + int fa1(int x) { return x; } + + int fa2(int x) { return x; } + auto fa2() { return this.fa2(123); } + + auto fb1() { int delegate(int) dg = &this.fb1; return dg(123); } + int fb1(int x) { return x; } + + int fb2(int x) { return x; } + auto fb2() { int delegate(int) dg = &this.fb2; return dg(123); } + + auto fc1() { auto dg = cast(int delegate(int))&this.fc1; return dg(123); } + int fc1(int x) { return x; } + + int fc2(int x) { return x; } + auto fc2() { auto dg = cast(int delegate(int))&this.fc2; return dg(123); } + + int delegate(int) fd1() { return &fd1; } + int fd1(int n) { return 10 + n; } + + int fd2(int n) { return 10 + n; } + int delegate(int) fd2() { return &fd2; } +} + +void test14965() +{ + assert(f14965a1() == 123); + assert(f14965b1() == 123); + assert(f14965c1() == 123); + assert(f14965d1()(113) == 123); + assert(f14965a2() == 123); + assert(f14965b2() == 123); + assert(f14965c2() == 123); + assert(f14965d2()(113) == 123); + + auto c = new C(); + assert(c.fa1() == 123); + assert(c.fb1() == 123); + assert(c.fc1() == 123); + assert(c.fd1()(113) == 123); + assert(c.fa2() == 123); + assert(c.fb2() == 123); + assert(c.fc2() == 123); + assert(c.fd2()(113) == 123); +} + /***************************************************/ int main() @@ -1170,6 +1246,7 @@ int main() test11916(); test13783(); test14858(); + test14965(); printf("Success\n"); return 0;