diff options
author | Jason Merrill <jason@redhat.com> | 2022-02-04 18:25:51 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2022-02-08 20:09:55 -0500 |
commit | 53cac72cf0821217f99d0640ba72cc2999ec7dc0 (patch) | |
tree | 39afa87017a50078ed99e8bb01e7e247b317246f /gcc | |
parent | 2a2fda2d9bebb9ef7fe4b9c8aa492a6517603e21 (diff) | |
download | gcc-53cac72cf0821217f99d0640ba72cc2999ec7dc0.zip gcc-53cac72cf0821217f99d0640ba72cc2999ec7dc0.tar.gz gcc-53cac72cf0821217f99d0640ba72cc2999ec7dc0.tar.bz2 |
c++: cleanup constant-init'd members [PR96876]
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.
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/typeck2.cc | 26 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base11.C | 19 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/eh/aggregate2.C | 27 |
3 files changed, 72 insertions, 0 deletions
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 4015bd5..39d03e4 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 0000000..88625dc --- /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 0000000..8424d63 --- /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 (); +} |