Now that we're building cleanups for aggregate elements more often, it seems worth optimizing by avoiding building one for the last element; once it is initialized, the complete object is fully initialized, the element cleanups end in favor of the complete object cleanup, and so a cleanup for the last element would guard nothing at all.
gcc/cp/ChangeLog: * typeck2.c (split_nonconstant_init_1): Don't cleanup the last elt. (split_nonconstant_init): Adjust. gcc/testsuite/ChangeLog: * g++.dg/tree-ssa/aggregate1.C: New test. --- gcc/cp/typeck2.c | 14 +++++++++----- gcc/testsuite/g++.dg/tree-ssa/aggregate1.C | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/aggregate1.C diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 7e7fc7f9f48..f439dd54866 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -486,7 +486,8 @@ maybe_push_temp_cleanup (tree sub, vec<tree,va_gc> **flags) generated statements. */ static bool -split_nonconstant_init_1 (tree dest, tree init, vec<tree,va_gc> **flags) +split_nonconstant_init_1 (tree dest, tree init, bool last, + vec<tree,va_gc> **flags) { unsigned HOST_WIDE_INT idx, tidx = HOST_WIDE_INT_M1U; tree field_index, value; @@ -545,9 +546,11 @@ split_nonconstant_init_1 (tree dest, tree init, vec<tree,va_gc> **flags) sub = build3 (COMPONENT_REF, inner_type, dest, field_index, NULL_TREE); + bool elt_last = last && idx == CONSTRUCTOR_NELTS (init) - 1; + if (TREE_CODE (value) == CONSTRUCTOR) { - if (!split_nonconstant_init_1 (sub, value, flags) + if (!split_nonconstant_init_1 (sub, value, elt_last, flags) /* For flexible array member with initializer we can't remove the initializer, because only the initializer determines how many elements the @@ -558,7 +561,7 @@ split_nonconstant_init_1 (tree dest, tree init, vec<tree,va_gc> **flags) && TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE && COMPLETE_TYPE_P (TREE_TYPE (value)) && !integer_zerop (TYPE_SIZE (TREE_TYPE (value))) - && idx == CONSTRUCTOR_NELTS (init) - 1 + && elt_last && TYPE_HAS_TRIVIAL_DESTRUCTOR (strip_array_types (inner_type)))) complete_p = false; @@ -634,7 +637,8 @@ split_nonconstant_init_1 (tree dest, tree init, vec<tree,va_gc> **flags) } code = build_stmt (input_location, EXPR_STMT, code); add_stmt (code); - maybe_push_temp_cleanup (sub, flags); + if (!elt_last) + maybe_push_temp_cleanup (sub, flags); } num_split_elts++; @@ -715,7 +719,7 @@ split_nonconstant_init (tree dest, tree init) if (TREE_CODE (TREE_TYPE (dest)) != ARRAY_TYPE) flags = make_tree_vector (); - if (split_nonconstant_init_1 (dest, init, &flags)) + if (split_nonconstant_init_1 (dest, init, true, &flags)) init = NULL_TREE; for (tree f : flags) diff --git a/gcc/testsuite/g++.dg/tree-ssa/aggregate1.C b/gcc/testsuite/g++.dg/tree-ssa/aggregate1.C new file mode 100644 index 00000000000..3f30a73b4e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/aggregate1.C @@ -0,0 +1,19 @@ +// Test that we don't bother building a cleanup for the last aggregate element. +// { dg-additional-options -fdump-tree-gimple } +// { dg-final { scan-tree-dump-not {A::~A \(&b\.a} "gimple" } } + +struct A +{ + A(int); + ~A(); +}; + +struct B +{ + A a; +}; + +int main() +{ + B b = { 1 }; +} -- 2.27.0