diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 334424770ef7..26852f6f2e36 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7360,6 +7360,7 @@ extern const char *cxx_printable_name_translate (tree, int); extern tree canonical_eh_spec (tree); extern tree build_cp_fntype_variant (tree, cp_ref_qualifier, tree, bool); extern tree build_exception_variant (tree, tree); +extern void fixup_deferred_exception_variants (tree, tree); extern tree bind_template_template_parm (tree, tree); extern tree array_type_nelts_total (tree); extern tree array_type_nelts_top (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index dd8c4b56bd06..274797f1879e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -24334,8 +24334,12 @@ cp_parser_class_specifier_1 (cp_parser* parser) /* Now we can parse the noexcept-specifier. */ spec = cp_parser_late_noexcept_specifier (parser, spec); - if (spec != error_mark_node) - TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec); + 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); /* Restore the state of local_variables_forbidden_p. */ parser->local_variables_forbidden_p = local_variables_forbidden_p; @@ -25371,6 +25375,9 @@ cp_parser_member_declaration (cp_parser* parser) int ctor_dtor_or_conv_p; bool static_p = (decl_specifiers.storage_class == sc_static); cp_parser_flags flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL; + /* We can't delay parsing for friends, + alias-declarations, and typedefs, even though the + standard seems to require it. */ if (!friend_p && !decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef)) flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT; @@ -26059,19 +26066,14 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, a class. So, if the noexcept-specifier has the optional expression, just save the tokens, and reparse this after we're done with the class. */ - const bool literal_p - = ((cp_lexer_nth_token_is (parser->lexer, 3, CPP_NUMBER) - || cp_lexer_nth_token_is (parser->lexer, 3, CPP_KEYWORD)) - && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_PAREN)); - if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN) + if ((flags & CP_PARSER_FLAGS_DELAY_NOEXCEPT) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN) /* No need to delay parsing for a number literal or true/false. */ - && !literal_p + && !((cp_lexer_nth_token_is (parser->lexer, 3, CPP_NUMBER) + || cp_lexer_nth_token_is (parser->lexer, 3, CPP_KEYWORD)) + && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_PAREN)) && at_class_scope_p () - /* We don't delay parsing for friend member functions, - alias-declarations, and typedefs, even though the standard seems - to require it. */ - && (flags & CP_PARSER_FLAGS_DELAY_NOEXCEPT) && TYPE_BEING_DEFINED (current_class_type) && !LAMBDA_TYPE_P (current_class_type)) return cp_parser_save_noexcept (parser); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 3087c4ab52c2..7e763479f7a9 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2676,6 +2676,52 @@ build_cp_fntype_variant (tree type, cp_ref_qualifier rqual, return v; } +/* TYPE is a function or method type with a deferred exception + specification that has been parsed to RAISES. Fixup all the type + variants that are affected in place. Via decltype &| noexcept + tricks, the unparsed spec could have escaped into the type system. + The general case is hard to fixup canonical types for. */ + +void +fixup_deferred_exception_variants (tree type, tree raises) +{ + 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); + + /* Though sucky, this walk will process the canonical variants + first. */ + for (tree variant = TYPE_MAIN_VARIANT (type); + variant; variant = TYPE_NEXT_VARIANT (variant)) + if (TYPE_RAISES_EXCEPTIONS (variant) == original) + { + gcc_checking_assert (variant != TYPE_MAIN_VARIANT (type)); + + if (!TYPE_STRUCTURAL_EQUALITY_P (variant)) + { + cp_cv_quals var_quals = TYPE_QUALS (variant); + cp_ref_qualifier rqual = type_memfn_rqual (variant); + + tree v = TYPE_MAIN_VARIANT (type); + for (; v; v = TYPE_NEXT_VARIANT (v)) + if (TYPE_CANONICAL (v) == v + && cp_check_qualified_type (v, variant, var_quals, + rqual, cr, false)) + break; + TYPE_RAISES_EXCEPTIONS (variant) = raises; + + if (!v) + v = build_cp_fntype_variant (TYPE_CANONICAL (variant), + rqual, cr, false); + TYPE_CANONICAL (variant) = v; + } + else + TYPE_RAISES_EXCEPTIONS (variant) = raises; + } +} + /* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions listed in RAISES. */