]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: extended temps and statement-exprs [PR118763]
authorJason Merrill <jason@redhat.com>
Sun, 16 Feb 2025 10:00:36 +0000 (11:00 +0100)
committerJason Merrill <jason@redhat.com>
Mon, 17 Feb 2025 17:19:25 +0000 (17:19 +0000)
My last patch for 118856 broke the test for 118763 (which my testing didn't
catch, for some reason), because it effectively reverted Jakub's recent fix
(r15-7415) for that bug.  It seems we need a new flag to indicate internal
temporaries.

In that patch Jakub wondered if other uses of CLEANUP_EH_ONLY would have the
same issue with jumps out of a statement-expr, and indeed it seems that
maybe_push_temp_cleanup and now set_up_extended_ref_temp have the same
problem.  Since maybe_push_temp_cleanup already uses a flag, we can easily
stop setting CLEANUP_EH_ONLY there as well.  Since set_up_extended_ref_temp
doesn't, working around this issue there will be more involved.

PR c++/118856
PR c++/118763

gcc/cp/ChangeLog:

* cp-tree.h (TARGET_EXPR_INTERNAL_P): New.
* call.cc (extend_temps_r): Check it instead of CLEANUP_EH_ONLY.
* tree.cc (get_internal_target_expr): Set it instead.
* typeck2.cc (maybe_push_temp_cleanup): Don't set CLEANUP_EH_ONLY.

gcc/testsuite/ChangeLog:

* g++.dg/ext/stmtexpr29.C: New test.

gcc/cp/call.cc
gcc/cp/cp-tree.h
gcc/cp/tree.cc
gcc/cp/typeck2.cc
gcc/testsuite/g++.dg/ext/stmtexpr29.C [new file with mode: 0644]

index 03130f80f861da25b5259fc1cf60dd4dbb2dd73a..be9b0cf62f103bc7f7289e0384431c2c38c3ca09 100644 (file)
@@ -14922,10 +14922,13 @@ extend_temps_r (tree *tp, int *walk_subtrees, void *data)
   if (TREE_CODE (*p) == TARGET_EXPR
       /* An eliding TARGET_EXPR isn't a temporary at all.  */
       && !TARGET_EXPR_ELIDING_P (*p)
-      /* A TARGET_EXPR with CLEANUP_EH_ONLY is an artificial variable used
-        during initialization, and need not be extended.  */
-      && !CLEANUP_EH_ONLY (*p))
+      /* A TARGET_EXPR with TARGET_EXPR_INTERNAL_P is an artificial variable
+        used during initialization that need not be extended.  */
+      && !TARGET_EXPR_INTERNAL_P (*p))
     {
+      /* A CLEANUP_EH_ONLY expr should also have TARGET_EXPR_INTERNAL_P.  */
+      gcc_checking_assert (!CLEANUP_EH_ONLY (*p));
+
       tree subinit = NULL_TREE;
       tree slot = TARGET_EXPR_SLOT (*p);
       *p = set_up_extended_ref_temp (d->decl, *p, d->cleanups, &subinit,
index 84bcbf29fa020c4994c0a2fcd448349df6992eaf..8866d5e2c2b9691fff8e0ebe69ed2e7e2fca0e0b 100644 (file)
@@ -514,6 +514,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       OVL_LOOKUP_P (in OVERLOAD)
       LOOKUP_FOUND_P (in RECORD_TYPE, UNION_TYPE, ENUMERAL_TYPE, NAMESPACE_DECL)
       FNDECL_MANIFESTLY_CONST_EVALUATED (in FUNCTION_DECL)
+      TARGET_EXPR_INTERNAL_P (in TARGET_EXPR)
    5: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
       CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
@@ -5608,6 +5609,11 @@ decl_template_parm_check (const_tree t, const char *f, int l, const char *fn)
 #define TARGET_EXPR_ELIDING_P(NODE) \
   TREE_LANG_FLAG_3 (TARGET_EXPR_CHECK (NODE))
 
+/* True if this TARGET_EXPR is for holding an implementation detail like a
+   cleanup flag or loop index, and should be ignored by extend_all_temps.  */
+#define TARGET_EXPR_INTERNAL_P(NODE) \
+  TREE_LANG_FLAG_4 (TARGET_EXPR_CHECK (NODE))
+
 /* True if NODE is a TARGET_EXPR that just expresses a copy of its INITIAL; if
    the initializer has void type, it's doing something more complicated.  */
 #define SIMPLE_TARGET_EXPR_P(NODE)                             \
index 611930b3c286d8f7f93a9a0f6be203d7ca2402f1..5628a576f01ba01e58218d5d6f90b72393a6c75b 100644 (file)
@@ -984,9 +984,7 @@ get_internal_target_expr (tree init)
   init = convert_bitfield_to_declared_type (init);
   tree t = build_target_expr_with_type (init, TREE_TYPE (init),
                                        tf_warning_or_error);
-  /* No internal variable should have a cleanup on the normal path, and
-     extend_temps_r checks this flag to decide whether to extend.  */
-  CLEANUP_EH_ONLY (t) = true;
+  TARGET_EXPR_INTERNAL_P (t) = true;
   return t;
 }
 
index 2555e9c1b6459659e00149b09ad458b2b4254d0f..1adc05aa86dc378257378a7cf10ee629c979ce05 100644 (file)
@@ -459,7 +459,6 @@ maybe_push_temp_cleanup (tree sub, vec<tree,va_gc> **flags)
     {
       tree tx = get_internal_target_expr (boolean_true_node);
       tree flag = TARGET_EXPR_SLOT (tx);
-      CLEANUP_EH_ONLY (tx) = true;
       TARGET_EXPR_CLEANUP (tx) = build3 (COND_EXPR, void_type_node,
                                         flag, cleanup, void_node);
       add_stmt (tx);
diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr29.C b/gcc/testsuite/g++.dg/ext/stmtexpr29.C
new file mode 100644 (file)
index 0000000..e797ed7
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+extern "C" void abort ();
+
+int a;
+struct A {
+  A() { ++a; }
+  A(int);
+  A(const A&);
+  ~A() { --a; }
+};
+
+struct B {
+  A a1;
+  A a2;
+};
+
+int main()
+{
+  {
+    B b = { A(), A(({goto out; 42;})) };
+  }
+ out:
+  if (a != 0)
+    abort ();
+}