mirror of
https://github.com/dlang/dmd.git
synced 2025-04-25 20:50:41 +03:00
fix issue 20562 returning __rvalue should move-construct the NRVO value (#20585)
This commit is contained in:
parent
6963395dc1
commit
cdc7334e44
3 changed files with 96 additions and 6 deletions
|
@ -818,20 +818,56 @@ extern(D) bool arrayExpressionSemantic(
|
|||
* e = the expression the needs to be moved or copied (source)
|
||||
* t = if the struct defines a copy constructor, the type of the destination (can be NULL)
|
||||
* nrvo = true if the generated copy can be treated as NRVO
|
||||
*
|
||||
* move = true to allow a move constructor to be used, false to prevent infinite recursion
|
||||
* Returns:
|
||||
* The expression that copy constructs or moves the value.
|
||||
*/
|
||||
extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t, bool nrvo)
|
||||
extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t, bool nrvo, bool move = false)
|
||||
{
|
||||
//printf("doCopyOrMove() %s\n", toChars(e));
|
||||
StructDeclaration sd;
|
||||
if (t)
|
||||
{
|
||||
if (auto ts = t.isTypeStruct())
|
||||
sd = ts.sym;
|
||||
}
|
||||
|
||||
if (auto ce = e.isCondExp())
|
||||
{
|
||||
ce.e1 = doCopyOrMove(sc, ce.e1, null, nrvo);
|
||||
ce.e2 = doCopyOrMove(sc, ce.e2, null, nrvo);
|
||||
}
|
||||
else if (e.isLvalue())
|
||||
{
|
||||
e = callCpCtor(sc, e, t, nrvo);
|
||||
}
|
||||
else if (move && sd && sd.hasMoveCtor && !e.isCallExp() && !e.isStructLiteralExp())
|
||||
{
|
||||
// #move
|
||||
/* Rewrite as:
|
||||
* S __copyrvalue;
|
||||
* __copyrvalue.moveCtor(e);
|
||||
* __copyrvalue;
|
||||
*/
|
||||
VarDeclaration vd = new VarDeclaration(e.loc, e.type, Identifier.generateId("__copyrvalue"), null);
|
||||
if (nrvo)
|
||||
vd.adFlags |= Declaration.nrvo;
|
||||
vd.storage_class |= STC.nodtor;
|
||||
vd.dsymbolSemantic(sc);
|
||||
Expression de = new DeclarationExp(e.loc, vd);
|
||||
Expression ve = new VarExp(e.loc, vd);
|
||||
|
||||
Expression er;
|
||||
er = new DotIdExp(e.loc, ve, Id.ctor); // ve.ctor
|
||||
er = new CallExp(e.loc, er, e); // ve.ctor(e)
|
||||
er = new CommaExp(e.loc, er, new VarExp(e.loc, vd)); // ve.ctor(e),vd
|
||||
er = Expression.combine(de, er); // de,ve.ctor(e),vd
|
||||
|
||||
e = er.expressionSemantic(sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
e = e.isLvalue() ? callCpCtor(sc, e, t, nrvo) : valueNoDtor(e);
|
||||
e = valueNoDtor(e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
@ -844,7 +880,7 @@ extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t, bool nrvo)
|
|||
* sc = just used to specify the scope of created temporary variable
|
||||
* destinationType = the type of the object on which the copy constructor is called;
|
||||
* may be null if the struct defines a postblit
|
||||
* nrvo = true if the generated copy can be treated as NRVO
|
||||
* nrvo = true if the generated copy can be treated as NRVO
|
||||
*/
|
||||
private Expression callCpCtor(Scope* sc, Expression e, Type destinationType, bool nrvo)
|
||||
{
|
||||
|
@ -865,7 +901,7 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType, boo
|
|||
*/
|
||||
VarDeclaration tmp = copyToTemp(STC.rvalue, "__copytmp", e);
|
||||
if (nrvo)
|
||||
tmp.adFlags |= Declaration.nrvo;
|
||||
tmp.adFlags |= Declaration.nrvo;
|
||||
if (sd.hasCopyCtor && destinationType)
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22619
|
||||
|
@ -893,6 +929,7 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType, boo
|
|||
*/
|
||||
Expression valueNoDtor(Expression e)
|
||||
{
|
||||
//printf("valueNoDtor() %s\n", toChars(e));
|
||||
auto ex = lastComma(e);
|
||||
|
||||
if (auto ce = ex.isCallExp())
|
||||
|
@ -10938,6 +10975,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
}
|
||||
else if (sd.hasMoveCtor && !e2x.isCallExp() && !e2x.isStructLiteralExp())
|
||||
{
|
||||
// #move
|
||||
/* The !e2x.isCallExp() is because it is already an rvalue
|
||||
and the move constructor is unnecessary:
|
||||
struct S {
|
||||
|
|
|
@ -940,7 +940,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
|||
* If NRVO is not possible, all returned lvalues should call their postblits.
|
||||
*/
|
||||
if (!funcdecl.isNRVO())
|
||||
exp = doCopyOrMove(sc2, exp, f.next, true);
|
||||
exp = doCopyOrMove(sc2, exp, f.next, true, true);
|
||||
|
||||
if (tret.hasPointers())
|
||||
checkReturnEscape(*sc2, exp, false);
|
||||
|
|
|
@ -139,6 +139,57 @@ void test7()
|
|||
StringTest s = StringTest(null);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
// https://github.com/dlang/dmd/issues/20562
|
||||
|
||||
struct S8
|
||||
{
|
||||
int a,b;
|
||||
this(S8) { printf("this(S)\n"); b = 4; }
|
||||
this(ref S8) { printf("this(ref S)\n"); assert(0); }
|
||||
}
|
||||
|
||||
|
||||
S8 returnRval(ref S8 arg)
|
||||
{
|
||||
static if (0)
|
||||
{
|
||||
/* __copytmp2 = 0 ;
|
||||
_D7rvalue51S6__ctorMFNcKSQxQrZQg call (arg param #__copytmp2);
|
||||
* __HID1 streq 1 __copytmp2;
|
||||
__HID1;
|
||||
*/
|
||||
return arg;
|
||||
}
|
||||
else static if (1)
|
||||
{
|
||||
/* * __HID1 streq 1 * arg;
|
||||
__HID1;
|
||||
*/
|
||||
return __rvalue(arg); // should move-construct the NRVO value
|
||||
}
|
||||
else
|
||||
{
|
||||
/* * t = 0 ;
|
||||
t;
|
||||
_TMP0 = t;
|
||||
_D7rvalue51S6__ctorMFNcSQwQqZQg call (arg param _TMP0);
|
||||
t;
|
||||
*/
|
||||
S8 t = __rvalue(arg);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test8()
|
||||
{
|
||||
S8 s;
|
||||
S8 t = returnRval(s);
|
||||
printf("t.b: %d\n", t.b);
|
||||
assert(t.b == 4);
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
int main()
|
||||
|
@ -150,6 +201,7 @@ int main()
|
|||
test5();
|
||||
test6();
|
||||
test7();
|
||||
test8();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue