diff --git a/src/dmd/escape.d b/src/dmd/escape.d index 9b40b34eb3b9..96d8ff3768b9 100644 --- a/src/dmd/escape.d +++ b/src/dmd/escape.d @@ -1651,7 +1651,19 @@ private void escapeByValue(Expression e, EscapeByResults* er) if ((stc & (STC.scope_)) && (stc & STC.return_)) arg.accept(this); else if ((stc & (STC.ref_)) && (stc & STC.return_)) - escapeByRef(arg, er); + { + if (tf.isref) + { + /* Treat: + * ref P foo(return ref P p) + * as: + * p; + */ + arg.accept(this); + } + else + escapeByRef(arg, er); + } } } } @@ -1666,7 +1678,19 @@ private void escapeByValue(Expression e, EscapeByResults* er) if (ad.isClassDeclaration() || tf.isscope) // this is 'return scope' dve.e1.accept(this); else if (ad.isStructDeclaration()) // this is 'return ref' - escapeByRef(dve.e1, er); + { + if (tf.isref) + { + /* Treat calling: + * struct S { ref S foo() return; } + * as: + * this; + */ + dve.e1.accept(this); + } + else + escapeByRef(dve.e1, er); + } } else if (dve.var.storage_class & STC.return_ || tf.isreturn) { diff --git a/test/compilable/fix20416.d b/test/compilable/fix20416.d new file mode 100644 index 000000000000..19ad74df1cf7 --- /dev/null +++ b/test/compilable/fix20416.d @@ -0,0 +1,36 @@ +/* REQUIRED_ARGS: -preview=dip1000 +*/ + +/********************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=20416 + +alias P = int*; + +ref P foo(return ref P); + +P bar() +{ + P result; + return foo(result); +} + + +/********************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=20416 + + +struct S +{ + string x; + ref S foo() return; +} + + +S bar2() +{ + S result; + return result.foo(); +} +