From: Marek Polacek Date: Fri, 8 Jan 2021 20:48:41 +0000 (-0500) Subject: c++: ICE when late parsing noexcept/NSDMI [PR98333] X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c37f1d4081f5a19e39192d13e2a3acea13662e5a;p=gcc.git c++: ICE when late parsing noexcept/NSDMI [PR98333] Since certain members of a class are a complete-class context [class.mem.general]p7, we delay their parsing untile the whole class has been parsed. For instance, NSDMIs and noexcept-specifiers. The order in which we perform this delayed parsing matters; we were first parsing NSDMIs and only they did we parse noexcept-specifiers. That turns out to be wrong: since NSDMIs may use noexcept-specifiers, we must process noexcept-specifiers first. Otherwise we'll ICE in code that doesn't expect to see DEFERRED_PARSE. This doesn't just shift the problem, noexcept-specifiers can use members with a NSDMI just fine, and I've also tested a similar test with this member function: bool f() { return __has_nothrow_constructor (S); } and that compiled fine too. gcc/cp/ChangeLog: PR c++/98333 * parser.c (cp_parser_class_specifier_1): Perform late-parsing of NSDMIs before late-parsing of noexcept-specifiers. gcc/testsuite/ChangeLog: PR c++/98333 * g++.dg/cpp0x/noexcept62.C: New test. --- diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e67339d56f9..5651cfacd3c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -25008,31 +25008,10 @@ cp_parser_class_specifier_1 (cp_parser* parser) maybe_end_member_template_processing (); } vec_safe_truncate (unparsed_funs_with_default_args, 0); - /* Now parse any NSDMIs. */ - save_ccp = current_class_ptr; - save_ccr = current_class_ref; - FOR_EACH_VEC_SAFE_ELT (unparsed_nsdmis, ix, decl) - { - if (class_type != DECL_CONTEXT (decl)) - { - if (pushed_scope) - pop_scope (pushed_scope); - class_type = DECL_CONTEXT (decl); - pushed_scope = push_scope (class_type); - } - inject_this_parameter (class_type, TYPE_UNQUALIFIED); - cp_parser_late_parsing_nsdmi (parser, decl); - } - vec_safe_truncate (unparsed_nsdmis, 0); - current_class_ptr = save_ccp; - current_class_ref = save_ccr; - if (pushed_scope) - pop_scope (pushed_scope); /* If there are noexcept-specifiers that have not yet been processed, - take care of them now. */ - class_type = NULL_TREE; - pushed_scope = NULL_TREE; + take care of them now. Do this before processing NSDMIs as they + may depend on noexcept-specifiers already having been processed. */ FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, decl) { tree ctx = DECL_CONTEXT (decl); @@ -25084,6 +25063,25 @@ cp_parser_class_specifier_1 (cp_parser* parser) maybe_end_member_template_processing (); } vec_safe_truncate (unparsed_noexcepts, 0); + + /* Now parse any NSDMIs. */ + save_ccp = current_class_ptr; + save_ccr = current_class_ref; + FOR_EACH_VEC_SAFE_ELT (unparsed_nsdmis, ix, decl) + { + if (class_type != DECL_CONTEXT (decl)) + { + if (pushed_scope) + pop_scope (pushed_scope); + class_type = DECL_CONTEXT (decl); + pushed_scope = push_scope (class_type); + } + inject_this_parameter (class_type, TYPE_UNQUALIFIED); + cp_parser_late_parsing_nsdmi (parser, decl); + } + vec_safe_truncate (unparsed_nsdmis, 0); + current_class_ptr = save_ccp; + current_class_ref = save_ccr; if (pushed_scope) pop_scope (pushed_scope); diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept62.C b/gcc/testsuite/g++.dg/cpp0x/noexcept62.C new file mode 100644 index 00000000000..53606c79142 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept62.C @@ -0,0 +1,10 @@ +// PR c++/98333 +// { dg-do compile { target c++11 } } + +struct T { + template + struct S { + S () noexcept (N) {} + }; + int a = __has_nothrow_constructor (S); +};