diff --git a/changelog/dip1000_deprecation_warnings.dd b/changelog/dip1000_deprecation_warnings.dd new file mode 100644 index 000000000000..8c21291ed819 --- /dev/null +++ b/changelog/dip1000_deprecation_warnings.dd @@ -0,0 +1,6 @@ +Print warning messages unless -revert=dip1000 is used + +As an incentive to transition to -preview=dip1000 by default, now the +compiler prints what would have been error messages if the flag had +been on as deprecation messages. This new behaviour can be disabled +with -revert=dip1000. diff --git a/src/dmd/escape.d b/src/dmd/escape.d index 78b9a07f3a37..44c3757248be 100644 --- a/src/dmd/escape.d +++ b/src/dmd/escape.d @@ -316,24 +316,27 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp */ void unsafeAssign(VarDeclaration v, const char* desc) { - if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()) + if (setUnsafeDIP1000(sc.func)) { if (!gag) { if (assertmsg) { - error(arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`", + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`", desc, v.toChars()); } else { - error(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s", + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s", desc, v.toChars(), par ? par.toChars() : "this", fdc ? fdc.toPrettyChars() : "indirectly"); } } - result = true; + if (global.params.useDIP1000 == FeatureState.enabled) + result = true; } } @@ -774,7 +777,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (v.isDataseg()) continue; - if (global.params.useDIP1000 == FeatureState.enabled) + if (global.params.useDIP1000 != FeatureState.disabled) { if (va && va.isScope() && !v.isReference()) { @@ -782,12 +785,18 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) { va.doNotInferReturn = true; } - else if (fd.setUnsafe()) + else if (setUnsafeDIP1000(fd)) { if (!gag) - error(ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars()); - result = true; - continue; + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars()); + + + if (global.params.useDIP1000 == FeatureState.enabled) + { + result = true; + continue; + } } } } @@ -976,12 +985,11 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag) if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown // despite being `scope` { + if (!gag) + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (e.loc, "scope variable `%s` may not be thrown", v.toChars()); if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029 - { - if (!gag) - error(e.loc, "scope variable `%s` may not be thrown", v.toChars()); result = true; - } continue; } else @@ -1042,13 +1050,16 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) */ !(p.parent == sc.func)) { - if (global.params.useDIP1000 == FeatureState.enabled // https://issues.dlang.org/show_bug.cgi?id=17029 - && sc.func.setUnsafe()) // https://issues.dlang.org/show_bug.cgi?id=20868 + if (setUnsafeDIP1000(sc.func)) // https://issues.dlang.org/show_bug.cgi?id=20868 { + // Only look for errors if in module listed on command line if (!gag) - error(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars()); - result = true; + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars()); + if (global.params.useDIP1000 == FeatureState.enabled) + result = true; } + continue; } } @@ -1258,11 +1269,13 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) ) { // https://issues.dlang.org/show_bug.cgi?id=17029 - if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()) + if (setUnsafeDIP1000(sc.func)) { if (!gag) - error(e.loc, "scope variable `%s` may not be returned", v.toChars()); - result = true; + previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) + (e.loc, "scope variable `%s` may not be returned", v.toChars()); + if (global.params.useDIP1000 == FeatureState.enabled) + result = true; } continue; } @@ -2341,3 +2354,11 @@ private void addMaybe(VarDeclaration va, VarDeclaration v) va.maybes = new VarDeclarations(); va.maybes.push(v); } + + +private bool setUnsafeDIP1000(FuncDeclaration f) +{ + return global.params.useDIP1000 == FeatureState.enabled + ? f.setUnsafe() + : f.isSafeBypassingInference(); +} diff --git a/test/fail_compilation/fail_scope.d b/test/fail_compilation/fail_scope.d index 41a8c2d85e3b..07c3766d4904 100644 --- a/test/fail_compilation/fail_scope.d +++ b/test/fail_compilation/fail_scope.d @@ -2,6 +2,13 @@ REQUIRED_ARGS: TEST_OUTPUT: --- +fail_compilation/fail_scope.d(29): Deprecation: scope variable `da` may not be returned +fail_compilation/fail_scope.d(31): Deprecation: scope variable `o` may not be returned +fail_compilation/fail_scope.d(32): Deprecation: scope variable `dg` may not be returned +fail_compilation/fail_scope.d(34): Deprecation: scope variable `da` may not be returned +fail_compilation/fail_scope.d(36): Deprecation: scope variable `o` may not be returned +fail_compilation/fail_scope.d(37): Deprecation: scope variable `dg` may not be returned +fail_compilation/fail_scope.d(39): Deprecation: scope variable `p` may not be returned fail_compilation/fail_scope.d(44): Error: returning `cast(char[])string` escapes a reference to local variable `string` fail_compilation/fail_scope.d(62): Error: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(73): Error: `fail_scope.foo8` called with argument types `(int)` matches both: @@ -15,26 +22,19 @@ fail_compilation/fail_scope.d(107): Deprecation: escaping reference to outer loc fail_compilation/fail_scope.d(126): Error: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(136): Error: returning `foo16226(i)` escapes a reference to local variable `i` --- -//fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned -//fail_compilation/fail_scope.d(32): Error: scope variable `o` may not be returned -//fail_compilation/fail_scope.d(33): Error: scope variable `dg` may not be returned -//fail_compilation/fail_scope.d(35): Error: scope variable `da` may not be returned -//fail_compilation/fail_scope.d(37): Error: scope variable `o` may not be returned -//fail_compilation/fail_scope.d(38): Error: scope variable `dg` may not be returned -//fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned */ alias int delegate() dg_t; -int[] checkEscapeScope1(scope int[] da) { return da; } -int[3] checkEscapeScope2(scope int[3] sa) { return sa; } -Object checkEscapeScope3(scope Object o) { return o; } -dg_t checkEscapeScope4(scope dg_t dg) { return dg; } +int[] checkEscapeScope1(scope int[] da) @safe { return da; } +int[3] checkEscapeScope2(scope int[3] sa) @safe { return sa; } +Object checkEscapeScope3(scope Object o) @safe { return o; } +dg_t checkEscapeScope4(scope dg_t dg) @safe { return dg; } -int[] checkEscapeScope1() { scope int[] da = []; return da; } -int[3] checkEscapeScope2() { scope int[3] sa = [1,2,3]; return sa; } -Object checkEscapeScope3() { scope Object o = new Object; return o; } // same with fail7294.d -dg_t checkEscapeScope4() { scope dg_t dg = () => 1; return dg; } +int[] checkEscapeScope1() @safe { scope int[] da = []; return da; } +int[3] checkEscapeScope2() @safe { scope int[3] sa = [1,2,3]; return sa; } +Object checkEscapeScope3() @safe { scope Object o = new Object; return o; } // same with fail7294.d +dg_t checkEscapeScope4() @safe { scope dg_t dg = () => 1; return dg; } int* test(scope int* p) @safe { return p; }