From patchwork Mon Sep 6 04:39:22 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: C++ PATCH to synthesized_method_walk Date: Sun, 05 Sep 2010 18:39:22 -0000 From: Jason Merrill X-Patchwork-Id: 63871 Message-Id: <4C84707A.2050201@redhat.com> To: gcc-patches List My earlier overhaul of implicit declarations to actually do overload resolution forgot to consider that constructors need to call destructors to cleanup the partially constructed object in case something throws an exception. This patch does that unless the constructor is trivial. Tested x86_64-pc-linux-gnu, applied to trunk. commit bb23019874834c4872a0f36bd2c8ee5256d7e86a Author: Jason Merrill Date: Mon Sep 6 00:15:56 2010 -0400 * method.c (synthesized_method_walk): In constructors, also check subobject destructors. diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 359e71d..0ec3826 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1052,10 +1052,15 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, int i, quals, flags; tsubst_flags_t complain; const char *msg; + bool ctor_p; + tree cleanup_spec; + bool cleanup_trivial = true; + bool cleanup_deleted = false; + cleanup_spec + = (cxx_dialect >= cxx0x ? noexcept_true_spec : empty_except_spec); if (spec_p) - *spec_p = (cxx_dialect >= cxx0x - ? noexcept_true_spec : empty_except_spec); + *spec_p = cleanup_spec; if (deleted_p) { @@ -1109,6 +1114,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, return; #endif + ctor_p = false; assign_p = false; check_vdtor = false; switch (sfk) @@ -1129,6 +1135,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, case sfk_constructor: case sfk_move_constructor: case sfk_copy_constructor: + ctor_p = true; fnname = complete_ctor_identifier; break; @@ -1176,7 +1183,16 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, - msg, BINFO_TYPE (base_binfo)); + msg, basetype); + if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) + { + /* In a constructor we also need to check the subobject + destructors for cleanup of partially constructed objects. */ + rval = locate_fn_flags (base_binfo, complete_dtor_identifier, + NULL_TREE, flags, complain); + process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial, + &cleanup_deleted, NULL, basetype); + } if (check_vdtor && type_has_virtual_destructor (basetype)) { @@ -1186,6 +1202,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, to have a null rval (no class-specific op delete). */ if (rval && rval == error_mark_node && deleted_p) *deleted_p = true; + check_vdtor = false; } } @@ -1206,12 +1223,20 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, "or trivial copy constructor"); FOR_EACH_VEC_ELT (tree, vbases, i, base_binfo) { + tree basetype = BINFO_TYPE (base_binfo); if (copy_arg_p) - argtype = build_stub_type (BINFO_TYPE (base_binfo), quals, move_p); + argtype = build_stub_type (basetype, quals, move_p); rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p, - msg, BINFO_TYPE (base_binfo)); + msg, basetype); + if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) + { + rval = locate_fn_flags (base_binfo, complete_dtor_identifier, + NULL_TREE, flags, complain); + process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial, + &cleanup_deleted, NULL, basetype); + } } } if (!diag) @@ -1225,12 +1250,26 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals, copy_arg_p, move_p, assign_p, spec_p, trivial_p, deleted_p, msg, flags, complain); + if (ctor_p) + walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier, + sfk_destructor, TYPE_UNQUALIFIED, false, + false, false, &cleanup_spec, &cleanup_trivial, + &cleanup_deleted, NULL, flags, complain); pop_scope (scope); --cp_unevaluated_operand; --c_inhibit_evaluation_warnings; + /* If the constructor isn't trivial, consider the subobject cleanups. */ + if (ctor_p && trivial_p && !*trivial_p) + { + if (deleted_p && cleanup_deleted) + *deleted_p = true; + if (spec_p) + *spec_p = merge_exception_specifiers (*spec_p, cleanup_spec); + } + #ifdef ENABLE_CHECKING /* If we expected this to be trivial but it isn't, then either we're in C++0x mode and this is a copy/move ctor/op= or there's an error. */ diff --git a/gcc/testsuite/g++.dg/cpp0x/implicit9.C b/gcc/testsuite/g++.dg/cpp0x/implicit9.C new file mode 100644 index 0000000..3a6dbc5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/implicit9.C @@ -0,0 +1,12 @@ +// Test that private base dtor makes derived ctor deleted +// { dg-options -std=c++0x } + +struct A +{ + A(); +private: + ~A(); // { dg-error "private" } +}; + +struct B: A { }; // { dg-error "implicitly deleted|context" } +B * b = new B; // { dg-error "deleted" }