Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions src/decl_inits.c
Original file line number Diff line number Diff line change
Expand Up @@ -4704,12 +4704,27 @@ 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);
is_var_init = dps != NULL && dps->sym != NULL &&
variable_for_symbol(dps->sym) != NULL;
/* In C++, the elements of a braced aggregate initializer are not separate
full-expressions: Temporaries created for them are destroyed when the
initialization of the whole aggregate is complete. GCC versions before
12 and MSVC instead destroy them at the end of each element in the
initializer of a variable (but not in other contexts, such as
mem-initializers and new-expressions). */
full_expression = !C_mode() && is->elements_are_full_expressions &&
is_aggregate_type(dtype) &&
!(dps != NULL && dps->is_struct_binding_decl) &&
!(is_var_init &&
(gpp_version_is(<120000) || microsoft_mode));
if (rescan_aggr != NULL) {
/* Rescan. The {...} is provided by the caller in init-component form. */
icp_tree = rescan_aggr;
Expand All @@ -4728,8 +4743,12 @@ initializer, already copied and substituted.
} /* if */
icp = icp_tree;
check_assertion(icp != NULL && is_braced_init_component(icp));
is_var_init = dps != NULL && dps->sym != NULL &&
variable_for_symbol(dps->sym) != NULL;
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 */
/* The force_dynamic_init flag only applies to the top-level result. */
is->force_dynamic_init = FALSE;
if (is_template_dependent_context() && is_variadic_template_context() &&
Expand Down Expand Up @@ -4933,6 +4952,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 */


Expand Down
3 changes: 3 additions & 0 deletions src/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -48020,11 +48020,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. */
Expand Down Expand Up @@ -48059,6 +48061,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. */
Expand Down
2 changes: 2 additions & 0 deletions src/lower_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -11048,6 +11048,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 &&

@daniel-petrovic daniel-petrovic Nov 4, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because of this it probably makes sense to add test for aggregate members with non-trivial destructors and member evaluations that throws exception mid-way through initialization

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added regressions/edg-29057-eh. It has members with nontrivial destructors, a nested aggregate, and exceptions thrown both during the initialization and after it, and it counts the constructions and destructions in each case. It passes in both x86_64 configurations.

latest_initialization_on_entry !=
eff_context->latest_initialization) {
/* This is an aggregate for which some partial-aggregate
Expand Down
18 changes: 18 additions & 0 deletions src/pending_changes/gh-515-aggregate-temporary-lifetime.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[GH #515]
Lifetime of temporaries in aggregate initialization

In C++, a temporary created in the initializer of an element of an aggregate
was destroyed at the end of that element's initialization in some contexts
(e.g., in the initializer of a variable, a mem-initializer, or a default
member initializer), instead of when the initialization of the whole
aggregate is complete. It is now destroyed at the end of the complete
initialization, including for nested aggregate initializers. When emulating
GCC versions before 12 or MSVC, which destroy such temporaries at the end of
each element in the initializer of a variable, that behavior is kept for
variables. For example:

struct Temp { Temp(); ~Temp(); };
struct A { A(const Temp&); };
struct Pair { A a; int b; };
int f();
Pair p{A(Temp{}), f()}; // The Temp is now still alive when f is called.
3 changes: 0 additions & 3 deletions tests/expectations/edg_x86_64/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -6644,7 +6644,6 @@ gnu/cpp/cpp0x/initlist-opt2.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp0x/initlist-ref1.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp0x/initlist-ref3.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp0x/initlist-value4.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp0x/initlist122.sft.cpp:rp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp0x/initlist13.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp0x/initlist36.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp0x/initlist55.sft.cpp:s:-DTEST_NUMBER=1 --c++11 -W:SKIPPED:
Expand Down Expand Up @@ -7721,10 +7720,8 @@ gnu/cpp/inherit/pr97268.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/inherit/using4.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/addr-const1.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/aggr4.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/init/aggr7-eh.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/aggr7-eh2.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/aggr7-eh3.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/array12.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/array44.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/brace4.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/copy3.sft.cpp:rp:-DTEST_NUMBER=1 --c++14:FAIL:
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/cwg/.cwg3100.rto/default.1.2.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
./a.out
~DTemp
~A
~A
~BTemp
~DTemp
~BTemp
Original file line number Diff line number Diff line change
Expand Up @@ -135,80 +135,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
check(t.x, " T", 0);
^

"test_passed.cpp", line 4301: error: static assertion failed with ""
static_assert(b.a.n == 4300, "");
^
"test_passed.cpp", line 4301: note: the final comparison was 4201 == 4300
static_assert(b.a.n == 4300, "");
^

"test_passed.cpp", line 4302: error: static assertion failed with ""
static_assert(b.a.n2 == 4300, "");
^
"test_passed.cpp", line 4302: note: the final comparison was 4201 == 4300
static_assert(b.a.n2 == 4300, "");
^

"test_passed.cpp", line 4303: error: static assertion failed with ""
static_assert(b.a.info.line() == 4300, "");
^
"test_passed.cpp", line 4303: note: the final comparison was 4201 == 4300
static_assert(b.a.info.line() == 4300, "");
^

"test_passed.cpp", line 4304: error: static assertion failed
static_assert(is_equal(b.a.f, "test_passed.cpp"));
^

"test_passed.cpp", line 4305: error: static assertion failed
static_assert(is_equal(b.a.f2, "test_passed.cpp"));
^

"test_passed.cpp", line 4306: error: static assertion failed
static_assert(is_equal(b.a.info.file(), "test_passed.cpp"));
^

"test_func_passed.cpp", line 4401: error: static assertion failed with ""
static_assert(b.a.n == 4400, "");
^
"test_func_passed.cpp", line 4401: note: the final comparison was 4201 == 4400
static_assert(b.a.n == 4400, "");
^

"test_func_passed.cpp", line 4402: error: static assertion failed with ""
static_assert(b.a.n2 == 4400, "");
^
"test_func_passed.cpp", line 4402: note: the final comparison was 4201 == 4400
static_assert(b.a.n2 == 4400, "");
^

"test_func_passed.cpp", line 4403: error: static assertion failed with ""
static_assert(b.a.info.line() == 4400, "");
^
"test_func_passed.cpp", line 4403: note: the final comparison was 4201 == 4400
static_assert(b.a.info.line() == 4400, "");
^

"test_func_passed.cpp", line 4404: error: static assertion failed
static_assert(is_equal(b.a.f, "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4405: error: static assertion failed
static_assert(is_equal(b.a.f2, "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4406: error: static assertion failed
static_assert(is_equal(b.a.info.file(), "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4407: error: static assertion failed
static_assert(is_equal(b.a.func, "test_in_func"));
^

"test_func_passed.cpp", line 4408: error: static assertion failed
static_assert(is_equal(b.a.func2, "test_in_func"));
^

"test_func_passed.cpp", line 4409: error: static assertion failed
static_assert(is_equal(b.a.info.function(), "bool test_out_of_line_init::test_in_func()"));
^
Expand Down Expand Up @@ -239,4 +165,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
^
detected during instantiation of "Pair<U, U> test_func::test_func_template(T, U) [with T=int, U=SL]" at line 361

39 errors detected in the compilation of "Test_name.c".
25 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -145,80 +145,6 @@ fe_only -DTEST_NUMBER=10 --clang -tused -e 200 --no_wrap_diagnostics --clang_ver
check(t.x, " T", 0);
^

"test_passed.cpp", line 4301: error: static assertion failed with ""
static_assert(b.a.n == 4300, "");
^
"test_passed.cpp", line 4301: note: the final comparison was 4201 == 4300
static_assert(b.a.n == 4300, "");
^

"test_passed.cpp", line 4302: error: static assertion failed with ""
static_assert(b.a.n2 == 4300, "");
^
"test_passed.cpp", line 4302: note: the final comparison was 4201 == 4300
static_assert(b.a.n2 == 4300, "");
^

"test_passed.cpp", line 4303: error: static assertion failed with ""
static_assert(b.a.info.line() == 4300, "");
^
"test_passed.cpp", line 4303: note: the final comparison was 4201 == 4300
static_assert(b.a.info.line() == 4300, "");
^

"test_passed.cpp", line 4304: error: static assertion failed
static_assert(is_equal(b.a.f, "test_passed.cpp"));
^

"test_passed.cpp", line 4305: error: static assertion failed
static_assert(is_equal(b.a.f2, "test_passed.cpp"));
^

"test_passed.cpp", line 4306: error: static assertion failed
static_assert(is_equal(b.a.info.file(), "test_passed.cpp"));
^

"test_func_passed.cpp", line 4401: error: static assertion failed with ""
static_assert(b.a.n == 4400, "");
^
"test_func_passed.cpp", line 4401: note: the final comparison was 4201 == 4400
static_assert(b.a.n == 4400, "");
^

"test_func_passed.cpp", line 4402: error: static assertion failed with ""
static_assert(b.a.n2 == 4400, "");
^
"test_func_passed.cpp", line 4402: note: the final comparison was 4201 == 4400
static_assert(b.a.n2 == 4400, "");
^

"test_func_passed.cpp", line 4403: error: static assertion failed with ""
static_assert(b.a.info.line() == 4400, "");
^
"test_func_passed.cpp", line 4403: note: the final comparison was 4201 == 4400
static_assert(b.a.info.line() == 4400, "");
^

"test_func_passed.cpp", line 4404: error: static assertion failed
static_assert(is_equal(b.a.f, "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4405: error: static assertion failed
static_assert(is_equal(b.a.f2, "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4406: error: static assertion failed
static_assert(is_equal(b.a.info.file(), "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4407: error: static assertion failed
static_assert(is_equal(b.a.func, "test_in_func"));
^

"test_func_passed.cpp", line 4408: error: static assertion failed
static_assert(is_equal(b.a.func2, "test_in_func"));
^

"test_func_passed.cpp", line 4409: error: static assertion failed
static_assert(is_equal(b.a.info.function(), "bool test_out_of_line_init::test_in_func()"));
^
Expand Down Expand Up @@ -286,4 +212,4 @@ fe_only -DTEST_NUMBER=10 --clang -tused -e 200 --no_wrap_diagnostics --clang_ver
^
detected during instantiation of "void test_func::inner::C<Ty>::df<T>(double) [with Ty=test_func::A, T=void]" at line 496

47 errors detected in the compilation of "Test_name.c".
33 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -135,80 +135,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
check(t.x, " T", 0);
^

"test_passed.cpp", line 4301: error: static assertion failed with ""
static_assert(b.a.n == 4300, "");
^
"test_passed.cpp", line 4301: note: the final comparison was 4201 == 4300
static_assert(b.a.n == 4300, "");
^

"test_passed.cpp", line 4302: error: static assertion failed with ""
static_assert(b.a.n2 == 4300, "");
^
"test_passed.cpp", line 4302: note: the final comparison was 4201 == 4300
static_assert(b.a.n2 == 4300, "");
^

"test_passed.cpp", line 4303: error: static assertion failed with ""
static_assert(b.a.info.line() == 4300, "");
^
"test_passed.cpp", line 4303: note: the final comparison was 4201 == 4300
static_assert(b.a.info.line() == 4300, "");
^

"test_passed.cpp", line 4304: error: static assertion failed
static_assert(is_equal(b.a.f, "test_passed.cpp"));
^

"test_passed.cpp", line 4305: error: static assertion failed
static_assert(is_equal(b.a.f2, "test_passed.cpp"));
^

"test_passed.cpp", line 4306: error: static assertion failed
static_assert(is_equal(b.a.info.file(), "test_passed.cpp"));
^

"test_func_passed.cpp", line 4401: error: static assertion failed with ""
static_assert(b.a.n == 4400, "");
^
"test_func_passed.cpp", line 4401: note: the final comparison was 4201 == 4400
static_assert(b.a.n == 4400, "");
^

"test_func_passed.cpp", line 4402: error: static assertion failed with ""
static_assert(b.a.n2 == 4400, "");
^
"test_func_passed.cpp", line 4402: note: the final comparison was 4201 == 4400
static_assert(b.a.n2 == 4400, "");
^

"test_func_passed.cpp", line 4403: error: static assertion failed with ""
static_assert(b.a.info.line() == 4400, "");
^
"test_func_passed.cpp", line 4403: note: the final comparison was 4201 == 4400
static_assert(b.a.info.line() == 4400, "");
^

"test_func_passed.cpp", line 4404: error: static assertion failed
static_assert(is_equal(b.a.f, "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4405: error: static assertion failed
static_assert(is_equal(b.a.f2, "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4406: error: static assertion failed
static_assert(is_equal(b.a.info.file(), "test_func_passed.cpp"));
^

"test_func_passed.cpp", line 4407: error: static assertion failed
static_assert(is_equal(b.a.func, "test_in_func"));
^

"test_func_passed.cpp", line 4408: error: static assertion failed
static_assert(is_equal(b.a.func2, "test_in_func"));
^

"test_func_passed.cpp", line 4409: error: static assertion failed
static_assert(is_equal(b.a.info.function(), "bool test_out_of_line_init::test_in_func()"));
^
Expand Down Expand Up @@ -239,4 +165,4 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
^
detected during instantiation of "Pair<U, U> test_func::test_func_template(T, U) [with T=int, U=SL]" at line 361

39 errors detected in the compilation of "Test_name.c".
25 errors detected in the compilation of "Test_name.c".
Loading
Loading