d: Fix LHS of array concatentation evaluated before the RHS.

In an array append expression:

    array ~= fun(array);

The array in the left hand side of the expression was extended before
evaluating the result of the right hand side, which resulted in the
newly uninitialized array index being used before set.

This fixes that so that the result of the right hand side is always
saved in a reusable temporary before assigning to the destination.

gcc/d/ChangeLog:

	PR d/97843
	* d-codegen.cc (build_assign): Evaluate TARGET_EXPR before use in
	the right hand side of an assignment.
	* expr.cc (ExprVisitor::visit (CatAssignExp *)): Force a TARGET_EXPR
	on the element to append if it is a CALL_EXPR.

gcc/testsuite/ChangeLog:

	PR d/97843
	* gdc.dg/torture/pr97843.d: New test.
This commit is contained in:
Iain Buclaw 2020-11-17 13:11:33 +01:00
parent 27d8c3516b
commit 798bdfa0eb
3 changed files with 44 additions and 1 deletions

View File

@ -1343,7 +1343,10 @@ build_assign (tree_code code, tree lhs, tree rhs)
since that would cause the LHS to be constructed twice.
So we force the TARGET_EXPR to be expanded without a target. */
if (code != INIT_EXPR)
rhs = compound_expr (rhs, TARGET_EXPR_SLOT (rhs));
{
init = compound_expr (init, rhs);
rhs = TARGET_EXPR_SLOT (rhs);
}
else
{
d_mark_addressable (lhs);

View File

@ -884,6 +884,9 @@ public:
tree t2 = build_expr (e->e2);
tree expr = stabilize_expr (&t2);
if (TREE_CODE (t2) == CALL_EXPR)
t2 = force_target_expr (t2);
result = modify_expr (build_deref (ptrexp), t2);
this->result_ = compound_expr (expr, result);

View File

@ -0,0 +1,37 @@
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97843
// { dg-additional-options "-fmain -funittest" }
// { dg-do run }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
struct Sdtor
{
int value;
~this() { }
}
Sdtor sum(Sdtor[] sdtors)
{
int result;
foreach (s; sdtors)
result += s.value;
return Sdtor(result);
}
uint sum(uint[] ints)
{
uint result;
foreach(i; ints)
result += i;
return result;
}
unittest
{
Sdtor[] sdtors = [Sdtor(0), Sdtor(1)];
sdtors ~= sum(sdtors);
assert(sdtors == [Sdtor(0), Sdtor(1), Sdtor(1)]);
uint[] ints = [0, 1];
ints ~= ints.sum;
assert(ints == [0, 1, 1]);
}