aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2021-01-08 15:48:41 -0500
committerMarek Polacek <polacek@redhat.com>2021-01-19 15:38:12 -0500
commitc37f1d4081f5a19e39192d13e2a3acea13662e5a (patch)
tree2b54eeb11741ed9b45176013a08267250ec546b6
parent7266ff2a243715e20882850b2fc4211ac7db4d34 (diff)
downloadgcc-c37f1d4081f5a19e39192d13e2a3acea13662e5a.zip
gcc-c37f1d4081f5a19e39192d13e2a3acea13662e5a.tar.gz
gcc-c37f1d4081f5a19e39192d13e2a3acea13662e5a.tar.bz2
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<true>); } 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.
-rw-r--r--gcc/cp/parser.c44
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/noexcept62.C10
2 files changed, 31 insertions, 23 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e67339d..5651cfa 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 0000000..53606c7
--- /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 <bool N>
+ struct S {
+ S () noexcept (N) {}
+ };
+ int a = __has_nothrow_constructor (S<true>);
+};