Skip to content

Commit 1d90597

Browse files
committed
Implement most RVO cases in glue layer
1 parent 414e335 commit 1d90597

8 files changed

Lines changed: 407 additions & 124 deletions

File tree

compiler/src/dmd/cxxfrontend.d

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,12 @@ bool isLvalue(Expression exp)
430430
return dmd.expressionsem.isLvalue(exp);
431431
}
432432

433+
bool canElideCopy(Expression exp, Type to, bool checkMod)
434+
{
435+
import dmd.expressionsem;
436+
return dmd.expressionsem.canElideCopy(exp, to, checkMod);
437+
}
438+
433439
int getFieldIndex(ClassReferenceExp cre, Type fieldtype, uint fieldoffset)
434440
{
435441
import dmd.expressionsem;

compiler/src/dmd/expression.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ namespace dmd
6262
bool isIdentical(const Expression *exp, const Expression *e);
6363
bool equals(const Expression *exp, const Expression *e);
6464
bool isLvalue(Expression *exp);
65+
bool canElideCopy(Expression *exp, Type *to, bool checkMod = true);
6566
int32_t getFieldIndex(ClassReferenceExp *cre, Type *fieldtype, uint32_t fieldoffset);
6667
void fillTupleExpExps(TupleExp *te, TupleDeclaration *tup);
6768
Optional<bool> toBool(Expression *exp);

compiler/src/dmd/expressionsem.d

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,19 @@ bool isLvalue(Expression _this)
681681
if (tf && tf.isRef)
682682
{
683683
if (auto dve = _this.e1.isDotVarExp())
684+
{
684685
if (dve.var.isCtorDeclaration())
685-
return false;
686+
{
687+
// Allow taking the address of explicit constructor calls,
688+
// but not (__stmp = S(), __stmp).__ctor().
689+
auto ve = lastComma(dve.e1).isVarExp();
690+
691+
if (ve && (ve.var.storage_class & STC.temp) != 0)
692+
return false;
693+
694+
return isLvalue(dve.e1);
695+
}
696+
}
686697
return true; // function returns a reference
687698
}
688699
return false;
@@ -761,6 +772,10 @@ bool isLvalue(Expression _this)
761772
* Determine if copy elision is allowed when copying an expression to
762773
* a typed storage. This basically elides a restricted subset of so-called
763774
* "pure" rvalues, i.e. expressions with no reference semantics.
775+
*
776+
* Note: Please try to keep `dmd.glue.e2ir.toElemRVO()` in sync with this.
777+
* It is not destructive to fail to elide a copy, but it is always better
778+
* to stay consistent.
764779
*/
765780
bool canElideCopy(Expression e, Type to, bool checkMod = true)
766781
{
@@ -770,8 +785,19 @@ bool canElideCopy(Expression e, Type to, bool checkMod = true)
770785
static bool visitCallExp(CallExp e)
771786
{
772787
if (auto dve = e.e1.isDotVarExp())
788+
{
773789
if (dve.var.isCtorDeclaration())
774-
return true;
790+
{
791+
// Allow (__stmp = S(), __stmp).__ctor() to be elided,
792+
// but force a copy for (s2 = s1.__ctor()).
793+
auto ve = lastComma(dve.e1).isVarExp();
794+
795+
if (ve && (ve.var.storage_class & STC.temp) != 0)
796+
return true;
797+
798+
return canElideCopy(dve.e1, e.type, false);
799+
}
800+
}
775801

776802
auto tb = e.e1.type.toBasetype();
777803
if (tb.ty == Tdelegate || tb.ty == Tpointer)
@@ -12303,7 +12329,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
1230312329
? cast(DotVarExp)ce.e1 : null;
1230412330
if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
1230512331
// https://issues.dlang.org/show_bug.cgi?id=19389
12306-
dve.e1.op != EXP.dotVariable &&
12332+
canElideCopy(ce, t1, false) &&
1230712333
e2y.type.implicitConvTo(t1))
1230812334
{
1230912335
/* Look for form of constructor call which is:
@@ -12414,7 +12440,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
1241412440
return;
1241512441
}
1241612442
}
12417-
else if (sd.hasMoveCtor && (!e2x.isCallExp() || e2x.rvalue) && !e2x.isStructLiteralExp())
12443+
else if (sd.hasMoveCtor && (e2x.rvalue || !canElideCopy(e2x, t1, false)))
1241812444
{
1241912445
// #move
1242012446
/* The !e2x.isCallExp() is because it is already an rvalue

0 commit comments

Comments
 (0)