aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2025-02-16 11:00:36 +0100
committerJason Merrill <jason@redhat.com>2025-02-17 17:19:25 +0000
commit720c8f685210af9fc9c31810e224751102f1481e (patch)
tree8d54d3c7310601b71c1081b6dbb5ddeb39c8882d
parent5954c5a7c23fbdf3afc011d703c9fce15db04cbd (diff)
downloadgcc-720c8f685210af9fc9c31810e224751102f1481e.zip
gcc-720c8f685210af9fc9c31810e224751102f1481e.tar.gz
gcc-720c8f685210af9fc9c31810e224751102f1481e.tar.bz2
c++: extended temps and statement-exprs [PR118763]
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.
-rw-r--r--gcc/cp/call.cc9
-rw-r--r--gcc/cp/cp-tree.h6
-rw-r--r--gcc/cp/tree.cc4
-rw-r--r--gcc/cp/typeck2.cc1
-rw-r--r--gcc/testsuite/g++.dg/ext/stmtexpr29.C27
5 files changed, 40 insertions, 7 deletions
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 03130f8..be9b0cf 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -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,
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 84bcbf2..8866d5e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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) \
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 611930b..5628a57 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -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;
}
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 2555e9c..1adc05a 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -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
index 0000000..e797ed7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/stmtexpr29.C
@@ -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 ();
+}