From bce68a5f34d1c30fcdadb1bf07316eead9ec1faf Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sun, 15 Mar 2020 03:08:58 -0700 Subject: [PATCH] fix Issue 20150 - -dip1000 return attribute must be explicit in pure functions --- src/dmd/escape.d | 26 ++++++++++++++++++++------ test/fail_compilation/fail20108.d | 2 +- test/fail_compilation/retscope6.d | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/dmd/escape.d b/src/dmd/escape.d index 8e6dafcefcbe..6cf61539c85c 100644 --- a/src/dmd/escape.d +++ b/src/dmd/escape.d @@ -1219,15 +1219,18 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) Dsymbol p = v.toParent2(); - if ((v.isScope() || (v.storage_class & STC.maybescope)) && - !(v.storage_class & STC.return_) && + bool needsReturn = false; + if (!(v.storage_class & STC.return_) && v.isParameter() && - !v.doNotInferReturn && - sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func) { - inferReturn(sc.func, v); // infer addition of 'return' - continue; + if ((v.isScope() || (v.storage_class & STC.maybescope)) && + sc.func.flags & FUNCFLAG.returnInprocess) + { + inferReturn(sc.func, v); // infer addition of 'return' + continue; + } + needsReturn = true; // needs 'return' annotation on parameter } if (v.isScope()) @@ -1275,6 +1278,17 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) result = false; } } + else if (needsReturn && sc.func.type.isTypeFunction().purity != PURE.impure && global.params.vsafe && + sc._module && sc._module.isRoot()) + { + /* Pure functions assume their parameters are `scope`, but they don't assume `return`. + * Hence, the annotation needs to be explicit. + */ + if (!gag) + error(e.loc, "`pure` function `%s` returns parameter `%s`, annotate with `return`", + sc.func.ident.toChars(), v.toChars()); + result = true; + } else { //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__); diff --git a/test/fail_compilation/fail20108.d b/test/fail_compilation/fail20108.d index 23e245f84a2f..dd2d5fb5e7bf 100644 --- a/test/fail_compilation/fail20108.d +++ b/test/fail_compilation/fail20108.d @@ -3,12 +3,12 @@ TEST_OUTPUT: --- fail_compilation/fail20108.d(15): Error: address of variable `y` assigned to `x` with longer lifetime -fail_compilation/fail20108.d(16): Error: scope variable `x` may not be returned fail_compilation/fail20108.d(23): Error: address of variable `y` assigned to `x` with longer lifetime fail_compilation/fail20108.d(24): Error: scope variable `x` may not be returned --- */ + @safe auto test(scope int* x) { int y = 69; diff --git a/test/fail_compilation/retscope6.d b/test/fail_compilation/retscope6.d index 4c48b9a8a8ec..b0c317892028 100644 --- a/test/fail_compilation/retscope6.d +++ b/test/fail_compilation/retscope6.d @@ -170,6 +170,22 @@ T9 testfred() return fred(&i); // error } + +/* TEST_OUTPUT: +--- +fail_compilation/retscope6.d(9505): Error: `pure` function `escape20150` returns parameter `r`, annotate with `return` +--- +*/ + +#line 9500 + +// https://issues.dlang.org/show_bug.cgi?id=20150 + +int* escape20150(int* r) @safe pure +{ + return r; +} + /* TEST_OUTPUT: --- fail_compilation/retscope6.d(10003): Error: scope variable `values` assigned to non-scope parameter `values` calling retscope6.escape