c++: TARGET_EXPR collapsing [PR107303]
authorJason Merrill <jason@redhat.com>
Mon, 23 Jan 2023 21:25:07 +0000 (16:25 -0500)
committerJason Merrill <jason@redhat.com>
Tue, 24 Jan 2023 03:26:24 +0000 (22:26 -0500)
In r13-2978 I tried to eliminate TARGET_EXPR around TARGET_EXPR by
discarding the outer one, but as in this testcase that breaks if the
TARGET_EXPR_SLOT of the outer one is used elsewhere.  But it should always
be safe to strip the inner one; if its slot were reused, there would be a
COMPOUND_EXPR around the TARGET_EXPR.

For 107329, if we're setting *walk_subtrees, we also need to fold
TARGET_EXPR_CLEANUP.

PR c++/107303
PR c++/107329

gcc/cp/ChangeLog:

* cp-gimplify.cc (cp_fold_r) [TARGET_EXPR]: In case of double
TARGET_EXPR, keep the outer one instead of the inner one.
(maybe_replace_decl): New.

gcc/testsuite/ChangeLog:

* g++.dg/ext/builtin-shufflevector-5.C: New test.
* g++.dg/init/new51.C: New test.

gcc/cp/cp-gimplify.cc
gcc/testsuite/g++.dg/ext/builtin-shufflevector-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/new51.C [new file with mode: 0644]

index 83ba128..92cd309 100644 (file)
@@ -952,6 +952,28 @@ cp_genericize_target_expr (tree *stmt_p)
   gcc_assert (!DECL_INITIAL (slot));
 }
 
+/* Similar to if (target_expr_needs_replace) replace_decl, but TP is the
+   TARGET_EXPR_INITIAL, and this also updates *_SLOT.  We need this extra
+   replacement when cp_folding TARGET_EXPR to preserve the invariant that
+   AGGR_INIT_EXPR_SLOT agrees with the enclosing TARGET_EXPR_SLOT.  */
+
+bool
+maybe_replace_decl (tree *tp, tree decl, tree replacement)
+{
+  if (!*tp || !VOID_TYPE_P (TREE_TYPE (*tp)))
+    return false;
+  tree t = *tp;
+  while (TREE_CODE (t) == COMPOUND_EXPR)
+    t = TREE_OPERAND (t, 1);
+  if (TREE_CODE (t) == AGGR_INIT_EXPR)
+    replace_decl (&AGGR_INIT_EXPR_SLOT (t), decl, replacement);
+  else if (TREE_CODE (t) == VEC_INIT_EXPR)
+    replace_decl (&VEC_INIT_EXPR_SLOT (t), decl, replacement);
+  else
+    replace_decl (tp, decl, replacement);
+  return true;
+}
+
 /* Genericization context.  */
 
 struct cp_genericize_data
@@ -1116,15 +1138,18 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
        cp_genericize_target_expr (stmt_p);
 
       /* Folding might replace e.g. a COND_EXPR with a TARGET_EXPR; in
-        that case, use it in place of this one.  */
+        that case, strip it in favor of this one.  */
       if (tree &init = TARGET_EXPR_INITIAL (stmt))
        {
          cp_walk_tree (&init, cp_fold_r, data, NULL);
+         cp_walk_tree (&TARGET_EXPR_CLEANUP (stmt), cp_fold_r, data, NULL);
          *walk_subtrees = 0;
          if (TREE_CODE (init) == TARGET_EXPR)
            {
-             TARGET_EXPR_ELIDING_P (init) = TARGET_EXPR_ELIDING_P (stmt);
-             *stmt_p = init;
+             tree sub = TARGET_EXPR_INITIAL (init);
+             maybe_replace_decl (&sub, TARGET_EXPR_SLOT (init),
+                                 TARGET_EXPR_SLOT (stmt));
+             init = sub;
            }
        }
       break;
diff --git a/gcc/testsuite/g++.dg/ext/builtin-shufflevector-5.C b/gcc/testsuite/g++.dg/ext/builtin-shufflevector-5.C
new file mode 100644 (file)
index 0000000..06472b8
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/107303
+// { dg-options "-Wno-psabi" }
+
+typedef __attribute__((__vector_size__ (2))) unsigned short U;
+typedef __attribute__((__vector_size__ (8))) unsigned short V;
+
+U u0, u1, u2;
+V v;
+
+void
+foo (void)
+{
+  u0 *= +__builtin_shufflevector (__builtin_shufflevector (u1, v, 3, 1), u2, 0);
+}
diff --git a/gcc/testsuite/g++.dg/init/new51.C b/gcc/testsuite/g++.dg/init/new51.C
new file mode 100644 (file)
index 0000000..d8b3364
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/107329
+
+struct RexxClass {
+  void *operator new(unsigned long, unsigned long, const char *, RexxClass *,
+                     RexxClass *);
+  void operator delete(void *, unsigned long, const char *, RexxClass *,
+                       RexxClass *);
+  RexxClass();
+};
+void createInstance() { new (sizeof(RexxClass), "", 0, 0) RexxClass; }