diff options
Diffstat (limited to 'gcc/d/dmd/escape.d')
-rw-r--r-- | gcc/d/dmd/escape.d | 112 |
1 files changed, 74 insertions, 38 deletions
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 4196c05489d..44c3757248b 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/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; } } @@ -440,22 +443,33 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp * sc = used to determine current function and module * firstArg = `ref` argument through which `arg` may be assigned * arg = initializer for parameter + * param = parameter declaration corresponding to `arg` * gag = do not print error messages * Returns: * `true` if assignment to `firstArg` would cause an error */ -bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, bool gag) +bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Parameter param, bool gag) { enum log = false; if (log) printf("checkParamArgumentReturn(firstArg: %s arg: %s)\n", firstArg.toChars(), arg.toChars()); //printf("type = %s, %d\n", arg.type.toChars(), arg.type.hasPointers()); - if (!arg.type.hasPointers()) + if (!(param.storageClass & STC.return_)) return false; + if (!arg.type.hasPointers() && !param.isReference()) + return false; + + // `byRef` needed for `assign(ref int* x, ref int i) {x = &i};` + // Note: taking address of scope pointer is not allowed + // `assign(ref int** x, return ref scope int* i) {x = &i};` + // Thus no return ref/return scope ambiguity here + const byRef = param.isReference() && !(param.storageClass & STC.scope_) + && !(param.storageClass & STC.returnScope); // fixme: it's possible to infer returnScope without scope with vaIsFirstRef + scope e = new AssignExp(arg.loc, firstArg, arg); - return checkAssignEscape(sc, e, gag); + return checkAssignEscape(sc, e, gag, byRef); } /***************************************************** @@ -496,23 +510,13 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag) foreach (const i; 0 .. n) { Expression arg = (*ce.arguments)[i]; - if (!arg.type.hasPointers()) - continue; - //printf("\targ[%d]: %s\n", i, arg.toChars()); if (i - j < nparams && i >= j) { Parameter p = tf.parameterList[i - j]; - - if (p.storageClass & STC.return_) - { - /* Fake `dve.e1 = arg;` and look for scope violations - */ - scope e = new AssignExp(arg.loc, dve.e1, arg); - if (checkAssignEscape(sc, e, gag)) - return true; - } + if (checkParamArgumentReturn(sc, dve.e1, arg, p, gag)) + return true; } } @@ -529,13 +533,14 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag) * sc = used to determine current function and module * e = `AssignExp` or `CatAssignExp` to check for any pointers to the stack * gag = do not print error messages + * byRef = set to `true` if `e1` of `e` gets assigned a reference to `e2` * Returns: * `true` if pointers to the stack can escape via assignment */ -bool checkAssignEscape(Scope* sc, Expression e, bool gag) +bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) { enum log = false; - if (log) printf("checkAssignEscape(e: %s)\n", e.toChars()); + if (log) printf("checkAssignEscape(e: %s, byRef: %d)\n", e.toChars(), byRef); if (e.op != EXP.assign && e.op != EXP.blit && e.op != EXP.construct && e.op != EXP.concatenateAssign && e.op != EXP.concatenateElemAssign && e.op != EXP.concatenateDcharAssign) return false; @@ -561,7 +566,10 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) EscapeByResults er; - escapeByValue(e2, &er); + if (byRef) + escapeByRef(e2, &er); + else + escapeByValue(e2, &er); if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim) return false; @@ -769,7 +777,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) if (v.isDataseg()) continue; - if (global.params.useDIP1000 == FeatureState.enabled) + if (global.params.useDIP1000 != FeatureState.disabled) { if (va && va.isScope() && !v.isReference()) { @@ -777,20 +785,36 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) { 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; + } } } } Dsymbol p = v.toParent2(); + if (vaIsFirstRef && v.isParameter() && + !(v.storage_class & STC.return_) && + fd.flags & FUNCFLAG.returnInprocess && + p == fd) + { + //if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars()); + inferReturn(fd, v, /*returnScope:*/ false); + } + // If va's lifetime encloses v's, then error if (va && + !(vaIsFirstRef && (v.storage_class & STC.return_)) && (va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) && fd.setUnsafe()) { @@ -961,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 @@ -1027,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; } } @@ -1243,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; } @@ -2326,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(); +} |