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 09:22:18 +0000 (10:22 +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/torture/pr97843.d: New test.

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

index 1f2d65c4ae2c458baf4452f6cdba21b38be9209a..4c16f6a822b34acc2dc4459f28c247be3f4fd741 100644 (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);
index 79f212c3a08f274b043e5e3c4531962b6f2ed3fe..ef2bf5f2e3689f508181263180a48e3ba5a16c7b 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/torture/pr97843.d b/gcc/testsuite/gdc.dg/torture/pr97843.d
new file mode 100644 (file)
index 0000000..1a417b3
--- /dev/null
@@ -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]);
+}