From d4e0bdbc036644401f9de49f594b2bb16b287381 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 5 Mar 2021 15:46:50 -0500 Subject: [PATCH] c++: ICE on invalid with inheriting constructors [PR94751] This is an ICE on invalid where we crash because since r269032 we keep error_mark_node around instead of using noexcept_false_spec when things go wrong; see the walk_field_subobs hunk. We crash in deduce_inheriting_ctor which calls synthesized_method_walk to deduce the exception-specification, but fails to do so in this case, because the testcase is invalid so get_nsdmi returns error_mark_node for the member 'c', and per r269032 the error_mark_node propagates back to deduce_inheriting_ctor which subsequently calls build_exception_variant whereon we crash. I think we should return early if the deduction fails and I decided to call mark_used to get an error right away instead of hoping that it would get called later. My worry is that we could forget that there was an error and think that we just deduced noexcept(false). And then I noticed that the test still crashes in C++98. Here again we failed to deduce the exception-specification in implicitly_declare_fn, but nothing reported an error between synthesized_method_walk and the assert. Well, not much we can do except calling synthesized_method_walk again, this time in the verbose mode and making sure that we did get an error. gcc/cp/ChangeLog: PR c++/94751 * call.c (build_over_call): Maybe call mark_used in case deduce_inheriting_ctor fails and return error_mark_node. * cp-tree.h (deduce_inheriting_ctor): Adjust declaration. * method.c (deduce_inheriting_ctor): Return bool if the deduction fails. (implicitly_declare_fn): If raises is error_mark_node, call synthesized_method_walk with diag being true. gcc/testsuite/ChangeLog: PR c++/94751 * g++.dg/cpp0x/inh-ctor37.C: New test. --- gcc/cp/call.c | 9 +++++++-- gcc/cp/cp-tree.h | 2 +- gcc/cp/method.c | 22 +++++++++++++++++----- gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C | 26 ++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e757e18..4b81d0f 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8947,8 +8947,13 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) /* OK, we're actually calling this inherited constructor; set its deletedness appropriately. We can get away with doing this here because calling is the only way to refer to a constructor. */ - if (DECL_INHERITED_CTOR (fn)) - deduce_inheriting_ctor (fn); + if (DECL_INHERITED_CTOR (fn) + && !deduce_inheriting_ctor (fn)) + { + if (complain & tf_error) + mark_used (fn); + return error_mark_node; + } /* Make =delete work with SFINAE. */ if (DECL_DELETED_FN (fn)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e68e390..f647052 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6915,7 +6915,7 @@ extern bool is_xible (enum tree_code, tree, tree); extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error); extern bool maybe_explain_implicit_delete (tree); extern void explain_implicit_non_constexpr (tree); -extern void deduce_inheriting_ctor (tree); +extern bool deduce_inheriting_ctor (tree); extern bool decl_remember_implicit_trigger_p (tree); extern void synthesize_method (tree); extern tree lazily_declare_fn (special_function_kind, diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 3fe3bd8..25c1e68 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -2789,9 +2789,9 @@ explain_implicit_non_constexpr (tree decl) /* DECL is an instantiation of an inheriting constructor template. Deduce the correct exception-specification and deletedness for this particular - specialization. */ + specialization. Return true if the deduction succeeds; false otherwise. */ -void +bool deduce_inheriting_ctor (tree decl) { decl = DECL_ORIGIN (decl); @@ -2804,6 +2804,8 @@ deduce_inheriting_ctor (tree decl) /*diag*/false, &inh, FUNCTION_FIRST_USER_PARMTYPE (decl)); + if (spec == error_mark_node) + return false; if (TREE_CODE (inherited_ctor_binfo (decl)) != TREE_BINFO) /* Inherited the same constructor from different base subobjects. */ deleted = true; @@ -2818,6 +2820,8 @@ deduce_inheriting_ctor (tree decl) TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), spec); SET_DECL_INHERITED_CTOR (clone, inh); } + + return true; } /* Implicitly declare the special function indicated by KIND, as a @@ -2993,9 +2997,17 @@ implicitly_declare_fn (special_function_kind kind, tree type, if (raises != error_mark_node) fn_type = build_exception_variant (fn_type, raises); else - /* Can happen, eg, in C++98 mode for an ill-formed non-static data - member initializer (c++/89914). */ - gcc_assert (seen_error ()); + { + /* Can happen, e.g., in C++98 mode for an ill-formed non-static data + member initializer (c++/89914). Also, in C++98, we might have + failed to deduce RAISES, so try again but complain this time. */ + if (cxx_dialect < cxx11) + synthesized_method_walk (type, kind, const_p, nullptr, nullptr, + nullptr, nullptr, /*diag=*/true, + &inherited_ctor, inherited_parms); + /* We should have seen an error at this point. */ + gcc_assert (seen_error ()); + } } fn = build_lang_decl (FUNCTION_DECL, name, fn_type); if (kind != sfk_inheriting_constructor) diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C new file mode 100644 index 0000000..7d12b53 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor37.C @@ -0,0 +1,26 @@ +// PR c++/94751 +// { dg-do compile } +// { dg-options "-w" } + +struct A { + A(float); +}; + +template +struct B : A { + using A::A; + + struct C { + C(int); + }; + + C c{ "foo" }; // { dg-error "invalid conversion" } +}; + +struct S { S(B *); }; + +S +fn () +{ + return S(new B(10.5)); // { dg-error "no matching function" "" { target c++98_only } } +} -- 2.7.4