Fix bugzilla 23657 - [REG2.101] Incorrect error escape reference to stack allocated value (#16407)

Co-authored-by: Dennis Korpel <dennis@sarc.nl>
This commit is contained in:
Dennis 2024-04-24 13:35:43 +02:00 committed by GitHub
parent 111ae7308b
commit 1da572ac2e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 6 deletions

View file

@ -1542,7 +1542,7 @@ private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
* e = expression to be returned by value * e = expression to be returned by value
* er = where to place collected data * er = where to place collected data
* live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`. * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
* retRefTransition = if `e` is returned through a `return ref scope` function call * retRefTransition = if `e` is returned through a `return (ref) scope` function call
*/ */
public public
void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false) void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
@ -1786,7 +1786,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
} }
} }
else else
escapeByValue(arg, er, live, retRefTransition); escapeByValue(arg, er, live, true);
} }
else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
{ {
@ -1941,7 +1941,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
* e = expression to be returned by 'ref' * e = expression to be returned by 'ref'
* er = where to place collected data * er = where to place collected data
* live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`. * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
* retRefTransition = if `e` is returned through a `return ref scope` function call * retRefTransition = if `e` is returned through a `return (ref) scope` function call
*/ */
private private
void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false) void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
@ -2189,7 +2189,7 @@ struct EscapeByResults
import dmd.root.array: Array; import dmd.root.array: Array;
/** /**
* Whether the variable / expression went through a `return ref scope` function call * Whether the variable / expression went through a `return (ref) scope` function call
* *
* This is needed for the dip1000 by default transition, since the rules for * This is needed for the dip1000 by default transition, since the rules for
* disambiguating `return scope ref` have changed. Therefore, functions in legacy code * disambiguating `return scope ref` have changed. Therefore, functions in legacy code
@ -2197,6 +2197,10 @@ struct EscapeByResults
* are being escaped, which is an error even in `@system` code. By keeping track of this * are being escaped, which is an error even in `@system` code. By keeping track of this
* information, variables escaped through `return ref` can be treated as a deprecation instead * information, variables escaped through `return ref` can be treated as a deprecation instead
* of error, see test/fail_compilation/dip1000_deprecation.d * of error, see test/fail_compilation/dip1000_deprecation.d
*
* Additionally, return scope can be inferred wrongly instead of scope, in which
* case the code could give false positives even without @safe or dip1000:
* https://issues.dlang.org/show_bug.cgi?id=23657
*/ */
private Array!bool refRetRefTransition; private Array!bool refRetRefTransition;
private Array!bool expRetRefTransition; private Array!bool expRetRefTransition;
@ -2218,7 +2222,7 @@ struct EscapeByResults
* Escape variable `v` by reference * Escape variable `v` by reference
* Params: * Params:
* v = variable to escape * v = variable to escape
* retRefTransition = `v` is escaped through a `return ref scope` function call * retRefTransition = `v` is escaped through a `return (ref) scope` function call
*/ */
void pushRef(VarDeclaration v, bool retRefTransition) void pushRef(VarDeclaration v, bool retRefTransition)
{ {
@ -2230,7 +2234,7 @@ struct EscapeByResults
* Escape a reference to expression `e` * Escape a reference to expression `e`
* Params: * Params:
* e = expression to escape * e = expression to escape
* retRefTransition = `e` is escaped through a `return ref scope` function call * retRefTransition = `e` is escaped through a `return (ref) scope` function call
*/ */
void pushExp(Expression e, bool retRefTransition) void pushExp(Expression e, bool retRefTransition)
{ {

View file

@ -0,0 +1,16 @@
// Stack pointers are being escaped here, but without
// @safe and dip1000, it should still be allowed
// because return scope could have been inferred incorrectly,
// and it breaks existing code:
// https://issues.dlang.org/show_bug.cgi?id=23657
int* identity(return scope int* x);
auto identityAuto(int* x) => x;
int* f()
{
int x;
return identity(&x);
return identityAuto(&x);
}