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);
/* 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;
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;
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);
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. */