This is a case missed by my recent fixes to aggregate initialization and exception cleanup for PR94041 et al: we also need to clean up members with constant initialization if initialization of a later member throws.
It also occurs to me that we needn't bother building the cleanups if -fno-exceptions; build_vec_init already doesn't. Tested x86_64-pc-linux-gnu, applying to trunk. PR c++/96876 gcc/cp/ChangeLog: * typeck2.cc (split_nonconstant_init_1): Push cleanups for preceding members with constant initialization. (maybe_push_temp_cleanup): Do nothing if -fno-exceptions. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/aggr-base11.C: New test. * g++.dg/eh/aggregate2.C: New test. --- gcc/cp/typeck2.cc | 26 +++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp1z/aggr-base11.C | 19 +++++++++++++++++ gcc/testsuite/g++.dg/eh/aggregate2.C | 27 ++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp1z/aggr-base11.C create mode 100644 gcc/testsuite/g++.dg/eh/aggregate2.C diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 4015bd53257..39d03e4c3c4 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -467,6 +467,8 @@ cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type) static void maybe_push_temp_cleanup (tree sub, vec<tree,va_gc> **flags) { + if (!flag_exceptions) + return; if (tree cleanup = cxx_maybe_build_cleanup (sub, tf_warning_or_error)) { @@ -496,6 +498,7 @@ split_nonconstant_init_1 (tree dest, tree init, bool last, bool array_type_p = false; bool complete_p = true; HOST_WIDE_INT num_split_elts = 0; + tree last_split_elt = NULL_TREE; switch (TREE_CODE (type)) { @@ -572,6 +575,7 @@ split_nonconstant_init_1 (tree dest, tree init, bool last, else { /* Mark element for removal. */ + last_split_elt = field_index; CONSTRUCTOR_ELT (init, idx)->index = NULL_TREE; if (idx < tidx) tidx = idx; @@ -584,6 +588,7 @@ split_nonconstant_init_1 (tree dest, tree init, bool last, flags)); /* Mark element for removal. */ + last_split_elt = field_index; CONSTRUCTOR_ELT (init, idx)->index = NULL_TREE; if (idx < tidx) tidx = idx; @@ -593,6 +598,26 @@ split_nonconstant_init_1 (tree dest, tree init, bool last, { tree code; + /* Push cleanups for any preceding members with constant + initialization. */ + if (CLASS_TYPE_P (type)) + for (tree prev = (last_split_elt ? + DECL_CHAIN (last_split_elt) + : TYPE_FIELDS (type)); + ; prev = DECL_CHAIN (prev)) + { + prev = next_initializable_field (prev); + if (prev == field_index) + break; + tree ptype = TREE_TYPE (prev); + if (type_build_dtor_call (ptype)) + { + tree pcref = build3 (COMPONENT_REF, ptype, dest, prev, + NULL_TREE); + maybe_push_temp_cleanup (pcref, flags); + } + } + /* Mark element for removal. */ CONSTRUCTOR_ELT (init, idx)->index = NULL_TREE; if (idx < tidx) @@ -645,6 +670,7 @@ split_nonconstant_init_1 (tree dest, tree init, bool last, maybe_push_temp_cleanup (sub, flags); } + last_split_elt = field_index; num_split_elts++; } } diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base11.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base11.C new file mode 100644 index 00000000000..88625dc9533 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base11.C @@ -0,0 +1,19 @@ +// PR c++/96876 +// { dg-do compile { target c++17 } } + +struct B { +protected: + ~B() {} // { dg-message "" } +}; + +struct A { }; +struct C1: B { int n; }; +struct C2: A, B { int n; }; + +A af (); +int f(); + +void g() { + C1 c1{ {}, f()}; // { dg-error "protected" } + C2 c2{ af(), {}, f()}; // { dg-error "protected" } +} diff --git a/gcc/testsuite/g++.dg/eh/aggregate2.C b/gcc/testsuite/g++.dg/eh/aggregate2.C new file mode 100644 index 00000000000..8424d63de2d --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/aggregate2.C @@ -0,0 +1,27 @@ +// PR c++/96876 +// { dg-do run { target c++11 } } + +int d; +struct B { + ~B() { ++d; } +}; + +struct C1 { B b; int n; }; +struct C2 { int i; B b; int n; }; + +int f() { throw 24; return 42; } +int dummy; +int g() { ++dummy; return 42; } + +int main() { + try { + C1 c{{}, f()}; + } catch (...) { } + + try { + C2 c{g(), {}, f()}; + } catch (...) { } + + if (d != 2) + __builtin_abort (); +} base-commit: 73f4a989b7f8aeaf8bff37e7f33b65d26b8f179f -- 2.27.0