]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
d: Fix LHS of array concatentation evaluated before the RHS.
authorIain Buclaw <ibuclaw@gdcproject.org>
Tue, 17 Nov 2020 12:11:33 +0000 (13:11 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Wed, 18 Nov 2020 10:31:58 +0000 (11:31 +0100)
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/pr97843.d: New test.

(cherry picked from commit 798bdfa0ebcf2bd012ffce75a594f783a8cb2dd0)

gcc/d/d-codegen.cc
gcc/d/expr.cc
gcc/testsuite/gdc.dg/pr97843.d [new file with mode: 0644]

index f57caf226d40aa2b63867d9c14b9a725f59b5f31..8042f03f369d692e5b6e3d3a2972250bec76d479 100644 (file)
@@ -1290,7 +1290,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);
index 9191d3a9510c8b25f8c0f248a70ada39307ffff2..acc54f39de39af75f631f2f043dff882c3a0ea1c 100644 (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);
diff --git a/gcc/testsuite/gdc.dg/pr97843.d b/gcc/testsuite/gdc.dg/pr97843.d
new file mode 100644 (file)
index 0000000..29a9d04
--- /dev/null
@@ -0,0 +1,37 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97843
+// { dg-additional-options "-fmain -funittest" }
+// { dg-do run { target hw } }
+// { 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]);
+}