diff --git a/src/decl_inits.c b/src/decl_inits.c index c077697a93..037e570ece 100644 --- a/src/decl_inits.c +++ b/src/decl_inits.c @@ -4704,12 +4704,17 @@ initializer, already copied and substituted. a_routine_ptr dtor_rp = NULL; a_boolean need_to_free_icp_tree = FALSE; a_boolean saved_reduce_backing_expression_use; + an_expr_stack_entry expr_stack_entry, *saved_expr_stack; + a_boolean full_expression; check_assertion(rescan_aggr != NULL || curr_token == tok_lbrace || (dps != NULL && anything_cached(&dps->prescanned_initializer_cache))); saved_reduce_backing_expression_use = reduce_backing_expression_use; dtype = skip_typerefs(dtype); + full_expression = !C_mode() && is->elements_are_full_expressions && + is_aggregate_type(dtype) && + !(dps != NULL && dps->is_struct_binding_decl); if (rescan_aggr != NULL) { /* Rescan. The {...} is provided by the caller in init-component form. */ icp_tree = rescan_aggr; @@ -4728,6 +4733,12 @@ initializer, already copied and substituted. } /* if */ icp = icp_tree; check_assertion(icp != NULL && is_braced_init_component(icp)); + if (full_expression) { + /* All elements share the lifetime of the complete initialization. */ + push_expr_stack_for_initializer(&expr_stack_entry, &saved_expr_stack, + ek_normal, + /*is_full_expr=*/TRUE, dps, is); + } /* if */ is_var_init = dps != NULL && dps->sym != NULL && variable_for_symbol(dps->sym) != NULL; /* The force_dynamic_init flag only applies to the top-level result. */ @@ -4933,6 +4944,17 @@ initializer, already copied and substituted. } /* if */ is->no_diagnostics = saved_no_diagnostics; reduce_backing_expression_use = saved_reduce_backing_expression_use; + if (full_expression) { + if (is->init_dip != NULL) { + wrap_up_dynamic_init_full_expression(is->init_dip); + } else if (is->init_error) { + discard_curr_expr_object_lifetime(); + } else if (is->init_con != NULL) { + wrap_up_constant_full_expression(is->init_con); + } /* if */ + pop_expr_stack_for_initializer(saved_expr_stack, + /*is_full_expr=*/TRUE, dps, is); + } /* if */ } /* braced_initializer */ diff --git a/src/expr.c b/src/expr.c index 67283dbc3a..4e8e6ccc33 100644 --- a/src/expr.c +++ b/src/expr.c @@ -47957,11 +47957,13 @@ free the components prior to prev_icp. an_expr_stack_entry *saved_expr_stack; an_expr_stack_entry expr_stack_entry; an_object_lifetime *saved_object_lifetime = curr_object_lifetime; + a_boolean saved_full_expressions; check_assertion(is_continuation_elem(prev_icp->next)); continuation = prev_icp->next->variant.continuation.state; dps = continuation->decl_parse_state; check_assertion(dps != NULL && dps->init_state.pending_elements); + saved_full_expressions = dps->init_state.elements_are_full_expressions; if (continuation->resumable) { /* Free most init components preceding prev_icp, but keep the first one in case it is useful for diagnostic purposes. */ @@ -47996,6 +47998,7 @@ free the components prior to prev_icp. /*bundle=*/TRUE, &continuation); pop_expr_stack_for_initializer(saved_expr_stack, /*is_full_expr=*/TRUE, dps, (an_init_state *)NULL); + dps->init_state.elements_are_full_expressions = saved_full_expressions; if (continuation != NULL) { /* Parsing was suspended again. Record additional state information to enable a subsequent call to this function. */ diff --git a/src/lower_init.c b/src/lower_init.c index f1965802ad..ad06c9251c 100644 --- a/src/lower_init.c +++ b/src/lower_init.c @@ -11022,6 +11022,8 @@ do_assignment:; /* coverity[uninit_use] */ if ((dip->kind == (a_dynamic_init_kind)dik_nonconstant_aggregate || dip->kind == (a_dynamic_init_kind)dik_lambda) && + /* Inner partial cleanups are handled by add_dyn_init_cleanup. */ + !dip->overlaps_temps_in_inner_lifetime && latest_initialization_on_entry != eff_context->latest_initialization) { /* This is an aggregate for which some partial-aggregate diff --git a/src/pending_changes/edg-29057-aggregate-temporary-lifetime.txt b/src/pending_changes/edg-29057-aggregate-temporary-lifetime.txt new file mode 100644 index 0000000000..135f9529ce --- /dev/null +++ b/src/pending_changes/edg-29057-aggregate-temporary-lifetime.txt @@ -0,0 +1,5 @@ +[GH #458] +Preserve aggregate initializer temporary lifetimes + +Temporaries created while initializing an aggregate now remain alive until +the complete initialization ends, including nested aggregate initializers. diff --git a/tests/tests/regressions/edg-29057.sft.cpp b/tests/tests/regressions/edg-29057.sft.cpp new file mode 100644 index 0000000000..694801f490 --- /dev/null +++ b/tests/tests/regressions/edg-29057.sft.cpp @@ -0,0 +1,21 @@ +//type:rp +//options_all:--c++20 +//options:--g++ --gnu_version=130300:--strict +int live, fails; +struct Temp { Temp() { ++live; } ~Temp() { --live; } }; +struct A { A(const Temp&) {} }; +struct Pair { A a; int b; }; +int check(int expected) { fails += live != expected; return 0; } +Pair make_pair() { return {A(Temp{}), check(1)}; } +int main() { + Pair p{A(Temp{}), check(1)}; + check(0); + Pair q = make_pair(); + check(0); + Pair a[2]{{A(Temp{}), check(1)}, {A(Temp{}), check(2)}}; + check(0); + struct Nested { Pair p; int c; } n{{A(Temp{}), check(1)}, check(1)}; + check(0); + (void)p; (void)q; (void)a; (void)n; + return fails; +}