diff options
author | Jason Merrill <jason@redhat.com> | 2025-02-16 11:00:36 +0100 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2025-02-17 17:19:25 +0000 |
commit | 720c8f685210af9fc9c31810e224751102f1481e (patch) | |
tree | 8d54d3c7310601b71c1081b6dbb5ddeb39c8882d | |
parent | 5954c5a7c23fbdf3afc011d703c9fce15db04cbd (diff) | |
download | gcc-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.cc | 9 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 6 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 4 | ||||
-rw-r--r-- | gcc/cp/typeck2.cc | 1 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/stmtexpr29.C | 27 |
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 (); +} |