Earlier changes to defer instantiating a defaulted noexcept-specifier that depends on yet-unparsed default member initializers broke this testcase, where instantiation fails for another reason. In this case there's no reason to defer and try again later, so let's not.
Tested x86_64-pc-linux-gnu, applying to trunk. * pt.c (maybe_instantiate_noexcept): Only return false if defaulted. (regenerate_decl_from_template): Use it for noexcept-specs. --- gcc/cp/pt.c | 34 +++++++++++++++++++------ gcc/testsuite/g++.dg/cpp0x/noexcept36.C | 22 ++++++++++++++++ gcc/cp/ChangeLog | 6 +++++ 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept36.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2ab6e273c3a..dc5c24c47a7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -23991,12 +23991,18 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args) if (args_depth > parms_depth) args = get_innermost_template_args (args, parms_depth); - specs = tsubst_exception_specification (TREE_TYPE (code_pattern), - args, tf_error, NULL_TREE, - /*defer_ok*/false); - if (specs && specs != error_mark_node) - TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), - specs); + /* Instantiate a dynamic exception-specification. noexcept will be + handled below. */ + if (tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (code_pattern))) + if (TREE_VALUE (raises)) + { + specs = tsubst_exception_specification (TREE_TYPE (code_pattern), + args, tf_error, NULL_TREE, + /*defer_ok*/false); + if (specs && specs != error_mark_node) + TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), + specs); + } /* Merge parameter declarations. */ decl_parm = skip_artificial_parms_for (decl, @@ -24062,6 +24068,8 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args) if (DECL_DECLARED_INLINE_P (code_pattern) && !DECL_DECLARED_INLINE_P (decl)) DECL_DECLARED_INLINE_P (decl) = 1; + + maybe_instantiate_noexcept (decl, tf_error); } else if (VAR_P (decl)) { @@ -24187,7 +24195,13 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) static hash_set<tree>* fns = new hash_set<tree>; bool added = false; if (DEFERRED_NOEXCEPT_PATTERN (noex) == NULL_TREE) - spec = get_defaulted_eh_spec (fn, complain); + { + spec = get_defaulted_eh_spec (fn, complain); + if (spec == error_mark_node) + /* This might have failed because of an unparsed DMI, so + let's try again later. */ + return false; + } else if (!(added = !fns->add (fn))) { /* If hash_set::add returns true, the element was already there. */ @@ -24247,7 +24261,11 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) fns->remove (fn); if (spec == error_mark_node) - return false; + { + /* This failed with a hard error, so let's go with false. */ + gcc_assert (seen_error ()); + spec = noexcept_false_spec; + } TREE_TYPE (fn) = build_exception_variant (fntype, spec); } diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept36.C b/gcc/testsuite/g++.dg/cpp0x/noexcept36.C new file mode 100644 index 00000000000..980a28cd207 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept36.C @@ -0,0 +1,22 @@ +// PR c++/89571 +// { dg-do compile { target c++11 } } + +struct z8 { + constexpr static int qq /* = 0 */; // { dg-error "initializer" } +}; + +template<typename T> +struct kf { + kf (const kf &) noexcept (T::qq); // { dg-error "constant" } +}; + +struct lk { + kf<z8> e1; +}; + +template<typename T> +T &sc (); + +struct b6 { + decltype (lk (sc<lk> ())) zz; +}; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6c96c24430f..8738f2c3cf4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2019-03-14 Jason Merrill <ja...@redhat.com> + + PR c++/89571 - ICE with ill-formed noexcept on constructor. + * pt.c (maybe_instantiate_noexcept): Only return false if defaulted. + (regenerate_decl_from_template): Use it for noexcept-specs. + 2019-03-14 Jason Merrill <ja...@redhat.com> * parser.c (cp_parser_decl_specifier_seq): Support C++20 base-commit: 6f9b555b441312235713247f996b67372efb8ddd -- 2.20.1