mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
d: RVO/NRVO not done when returning a copy constructor
RVO was already being done when returning a constructor call via a
temporary, which in the front-end AST looks like:
return S.this((__tmp = {}, &__tmp), args...);
But this was not being done for copy construction calls, which instead
looks like:
return __copytmp = {}, S.this(&__copytmp, V(1).s), __copytmp;
This pattern is now matched and the temporary gets set up as a
DECL_VALUE_EXPR of the RESULT_DECL.
PR d/123422
gcc/d/ChangeLog:
* expr.cc (ExprVisitor::visit (ArrayLiteralExp *)): Don't add
TARGET_EXPR around constructor.
* toir.cc (IRVisitor::visit (ReturnStatement *)): Recognize more
patterns for return value optimization.
gcc/testsuite/ChangeLog:
* gdc.dg/torture/pr123422.d: New test.
This commit is contained in:
@@ -2675,7 +2675,7 @@ public:
|
||||
gcc_assert (tb->ty == TY::Tarray);
|
||||
ctor = force_target_expr (ctor);
|
||||
ctor = d_array_value (type, size_int (e->elements->length),
|
||||
build_address (force_target_expr (ctor)));
|
||||
build_address (ctor));
|
||||
this->result_ = compound_expr (saved_elems, ctor);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1022,41 +1022,64 @@ public:
|
||||
/* Detect a call to a constructor function, or if returning a struct
|
||||
literal, write result directly into the return value. */
|
||||
StructLiteralExp *sle = NULL;
|
||||
DeclarationExp *de = NULL;
|
||||
VarExp *ve = NULL;
|
||||
bool using_rvo_p = false;
|
||||
|
||||
if (DotVarExp *dve = (s->exp->isCallExp ()
|
||||
? s->exp->isCallExp ()->e1->isDotVarExp ()
|
||||
: NULL))
|
||||
{
|
||||
/* Look for `var.__ctor(copytmp = {}, ©tmp)' */
|
||||
if (dve->var->isCtorDeclaration ())
|
||||
{
|
||||
if (CommaExp *ce = dve->e1->isCommaExp ())
|
||||
{
|
||||
/* Temporary initialized inside a return expression, and
|
||||
used as the return value. Replace it with the hidden
|
||||
reference to allow RVO return. */
|
||||
DeclarationExp *de = ce->e1->isDeclarationExp ();
|
||||
VarExp *ve = ce->e2->isVarExp ();
|
||||
if (de != NULL && ve != NULL
|
||||
&& ve->var == de->declaration
|
||||
&& ve->var->storage_class & STCtemp)
|
||||
{
|
||||
tree var = get_symbol_decl (ve->var);
|
||||
TREE_ADDRESSABLE (var) = 1;
|
||||
SET_DECL_VALUE_EXPR (var, decl);
|
||||
DECL_HAS_VALUE_EXPR_P (var) = 1;
|
||||
SET_DECL_LANG_NRVO (var, this->func_->shidden);
|
||||
using_rvo_p = true;
|
||||
}
|
||||
de = ce->e1->isDeclarationExp ();
|
||||
ve = ce->e2->isVarExp ();
|
||||
}
|
||||
else
|
||||
sle = dve->e1->isStructLiteralExp ();
|
||||
}
|
||||
}
|
||||
else if (CommaExp *ce1 = s->exp->isCommaExp ())
|
||||
{
|
||||
/* Look for `copytmp = {}, copytmp.__ctor(), copytmp' */
|
||||
if (CommaExp *ce2 = ce1->e2->isCommaExp ())
|
||||
{
|
||||
DotVarExp *dve = ce2->e1->isCallExp ()
|
||||
? ce2->e1->isCallExp ()->e1->isDotVarExp () : NULL;
|
||||
|
||||
if (dve && dve->var->isCtorDeclaration ())
|
||||
{
|
||||
de = ce1->e1->isDeclarationExp ();
|
||||
ve = ce2->e2->isVarExp ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
de = ce1->e1->isDeclarationExp ();
|
||||
ve = ce1->e2->isVarExp ();
|
||||
}
|
||||
}
|
||||
else
|
||||
sle = s->exp->isStructLiteralExp ();
|
||||
|
||||
if (sle != NULL)
|
||||
if (de != NULL && ve != NULL
|
||||
&& ve->var == de->declaration
|
||||
&& ve->var->storage_class & STCtemp)
|
||||
{
|
||||
/* Temporary initialized inside a return expression, and
|
||||
used as the return value. Replace it with the hidden
|
||||
reference to allow RVO return. */
|
||||
tree var = get_symbol_decl (ve->var);
|
||||
TREE_ADDRESSABLE (var) = 1;
|
||||
SET_DECL_VALUE_EXPR (var, decl);
|
||||
DECL_HAS_VALUE_EXPR_P (var) = 1;
|
||||
SET_DECL_LANG_NRVO (var, this->func_->shidden);
|
||||
using_rvo_p = true;
|
||||
}
|
||||
else if (sle != NULL)
|
||||
{
|
||||
sle->sym = build_address (this->func_->shidden);
|
||||
using_rvo_p = true;
|
||||
|
||||
25
gcc/testsuite/gdc.dg/torture/pr123422.d
Normal file
25
gcc/testsuite/gdc.dg/torture/pr123422.d
Normal file
@@ -0,0 +1,25 @@
|
||||
// { dg-do run }
|
||||
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
|
||||
struct S123422
|
||||
{
|
||||
S123422* ptr;
|
||||
this(int) { ptr = &this; }
|
||||
this(ref inout S123422) { ptr = &this; }
|
||||
}
|
||||
|
||||
struct V123422
|
||||
{
|
||||
S123422 s;
|
||||
this(int) { s = S123422(1); }
|
||||
}
|
||||
|
||||
S123422 foo()
|
||||
{
|
||||
return V123422(1).s;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S123422 s = foo();
|
||||
assert(&s == s.ptr);
|
||||
}
|
||||
Reference in New Issue
Block a user