pushed_scope = push_scope (class_type);
}
- tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
- spec = TREE_PURPOSE (spec);
+ tree def_parse = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl));
+ def_parse = TREE_PURPOSE (def_parse);
/* Make sure that any template parameters are in scope. */
maybe_begin_member_template_processing (decl);
parser->local_variables_forbidden_p |= THIS_FORBIDDEN;
/* Now we can parse the noexcept-specifier. */
- spec = cp_parser_late_noexcept_specifier (parser, spec);
+ tree spec = cp_parser_late_noexcept_specifier (parser, def_parse);
if (spec == error_mark_node)
spec = NULL_TREE;
/* Update the fn's type directly -- it might have escaped
beyond this decl :( */
fixup_deferred_exception_variants (TREE_TYPE (decl), spec);
+ /* Update any instantiations we've already created. We must
+ keep the new noexcept-specifier wrapped in a DEFERRED_NOEXCEPT
+ so that maybe_instantiate_noexcept can tsubst the NOEXCEPT_EXPR
+ in the pattern. */
+ for (tree i : DEFPARSE_INSTANTIATIONS (def_parse))
+ DEFERRED_NOEXCEPT_PATTERN (TREE_PURPOSE (i)) = TREE_PURPOSE (spec);
/* Restore the state of local_variables_forbidden_p. */
parser->local_variables_forbidden_p = local_variables_forbidden_p;
/* Save away the noexcept-specifier; we will process it when the
class is complete. */
DEFPARSE_TOKENS (expr) = cp_token_cache_new (first, last);
+ DEFPARSE_INSTANTIATIONS (expr) = nullptr;
expr = build_tree_list (expr, NULL_TREE);
return expr;
}
/*integral_constant_expression_p=*/true);
}
new_specs = build_noexcept_spec (new_specs, complain);
+ /* We've instantiated a template before a noexcept-specifier
+ contained therein has been parsed. This can happen for
+ a nested template class:
+
+ struct S {
+ template<typename> struct B { B() noexcept(...); };
+ struct A : B<int> { ... use B() ... };
+ };
+
+ where completing B<int> will trigger instantiating the
+ noexcept, even though we only parse it at the end of S. */
+ if (UNPARSED_NOEXCEPT_SPEC_P (specs))
+ {
+ gcc_checking_assert (defer_ok);
+ vec_safe_push (DEFPARSE_INSTANTIATIONS (expr), new_specs);
+ }
}
else if (specs)
{
tree original = TYPE_RAISES_EXCEPTIONS (type);
tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
- gcc_checking_assert (TREE_CODE (TREE_PURPOSE (original))
- == DEFERRED_PARSE);
+ gcc_checking_assert (UNPARSED_NOEXCEPT_SPEC_P (original));
/* Though sucky, this walk will process the canonical variants
first. */
--- /dev/null
+// PR c++/98899
+// { dg-do compile { target c++11 } }
+
+template <int __v> struct integral_constant {
+ static constexpr int value = __v;
+};
+
+struct S {
+ template<class> struct B {
+ B() noexcept(noexcept(x));
+ int x;
+ };
+ struct A : B<int> {
+ A() : B() {}
+ };
+};
+
+struct S2 {
+ template<class> struct B {
+ B() noexcept(integral_constant<false>::value);
+ };
+ struct A : B<int> {
+ A() : B() {}
+ };
+};
+
+struct S3 {
+ template<class> struct B {
+ B() noexcept(b);
+ };
+ struct A : B<int> {
+ A() : B() {}
+ };
+ static constexpr bool b = false;
+};