summaryrefslogtreecommitdiff
path: root/gcc/d/dmd/escape.d
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/escape.d')
-rw-r--r--gcc/d/dmd/escape.d112
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();
+}