diff options
author | Marek Polacek <polacek@redhat.com> | 2019-06-22 15:14:30 +0000 |
---|---|---|
committer | Marek Polacek <mpolacek@gcc.gnu.org> | 2019-06-22 15:14:30 +0000 |
commit | 78f7607db4c53f8cfe4653a6c91c0328bc2854c3 (patch) | |
tree | d8c288e122322c16f7c0c600df65e9b34feaf7c2 /gcc/cp | |
parent | 7f3db013dc8264e39339ee4b83900ef25d0d32aa (diff) | |
download | gcc-78f7607db4c53f8cfe4653a6c91c0328bc2854c3.zip gcc-78f7607db4c53f8cfe4653a6c91c0328bc2854c3.tar.gz gcc-78f7607db4c53f8cfe4653a6c91c0328bc2854c3.tar.bz2 |
PR c++/86476 - noexcept-specifier is a complete-class context.
PR c++/52869
* cp-tree.def (DEFAULT_ARG): Update commentary.
* cp-tree.h (UNPARSED_NOEXCEPT_SPEC_P): New macro.
(tree_default_arg): Use tree_base instead of tree_common.
(do_push_parm_decls, maybe_check_overriding_exception_spec): Declare.
* decl.c (do_push_parm_decls): New function, broken out of...
(store_parm_decls): ...here. Call it.
* except.c (nothrow_spec_p): Accept DEFAULT_ARG in the assert.
* parser.c (cp_parser_noexcept_specification_opt,
cp_parser_late_noexcept_specifier, noexcept_override_late_checks):
Forward-declare.
(unparsed_noexcepts): New macro.
(push_unparsed_function_queues): Update initializer.
(cp_parser_direct_declarator): Pass FRIEND_P to
cp_parser_exception_specification_opt.
(inject_parm_decls): New.
(pop_injected_parms): New.
(cp_parser_class_specifier_1): Implement delayed parsing of
noexcept-specifiers.
(cp_parser_save_noexcept): New.
(cp_parser_late_noexcept_specifier): New.
(noexcept_override_late_checks): New.
(cp_parser_noexcept_specification_opt): Add FRIEND_P parameter. Call
cp_parser_save_noexcept instead of the normal processing if needed.
(cp_parser_exception_specification_opt): Add FRIEND_P parameter and
pass it to cp_parser_noexcept_specification_opt.
(cp_parser_save_member_function_body): Fix comment.
(cp_parser_save_default_args): Maybe save the noexcept-specifier to
post process.
(cp_parser_transaction): Update call to
cp_parser_noexcept_specification_opt.
(cp_parser_transaction_expression): Likewise.
* parser.h (cp_unparsed_functions_entry): Add new field to carry
a noexcept-specifier.
* pt.c (dependent_type_p_r): Handle unparsed noexcept expression.
* search.c (maybe_check_overriding_exception_spec): New function, broken
out of...
(check_final_overrider): ...here. Call
maybe_check_overriding_exception_spec.
* tree.c (canonical_eh_spec): Handle UNPARSED_NOEXCEPT_SPEC_P.
(cp_tree_equal): Handle DEFAULT_ARG.
* g++.dg/cpp0x/noexcept45.C: New test.
* g++.dg/cpp0x/noexcept46.C: New test.
* g++.dg/cpp0x/noexcept47.C: New test.
* g++.dg/cpp0x/noexcept48.C: New test.
* g++.dg/cpp0x/noexcept49.C: New test.
* g++.dg/cpp0x/noexcept50.C: New test.
* g++.dg/cpp0x/noexcept51.C: New test.
* g++.dg/cpp0x/noexcept52.C: New test.
* g++.dg/cpp0x/noexcept53.C: New test.
* g++.dg/eh/shadow1.C: Adjust dg-error.
From-SVN: r272586
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 43 | ||||
-rw-r--r-- | gcc/cp/cp-tree.def | 3 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 7 | ||||
-rw-r--r-- | gcc/cp/decl.c | 59 | ||||
-rw-r--r-- | gcc/cp/except.c | 1 | ||||
-rw-r--r-- | gcc/cp/parser.c | 240 | ||||
-rw-r--r-- | gcc/cp/parser.h | 3 | ||||
-rw-r--r-- | gcc/cp/pt.c | 3 | ||||
-rw-r--r-- | gcc/cp/search.c | 51 | ||||
-rw-r--r-- | gcc/cp/tree.c | 2 |
10 files changed, 355 insertions, 57 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 31336f9..800ae29 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,48 @@ 2019-06-22 Marek Polacek <polacek@redhat.com> + PR c++/86476 - noexcept-specifier is a complete-class context. + PR c++/52869 + * cp-tree.def (DEFAULT_ARG): Update commentary. + * cp-tree.h (UNPARSED_NOEXCEPT_SPEC_P): New macro. + (tree_default_arg): Use tree_base instead of tree_common. + (do_push_parm_decls, maybe_check_overriding_exception_spec): Declare. + * decl.c (do_push_parm_decls): New function, broken out of... + (store_parm_decls): ...here. Call it. + * except.c (nothrow_spec_p): Accept DEFAULT_ARG in the assert. + * parser.c (cp_parser_noexcept_specification_opt, + cp_parser_late_noexcept_specifier, noexcept_override_late_checks): + Forward-declare. + (unparsed_noexcepts): New macro. + (push_unparsed_function_queues): Update initializer. + (cp_parser_direct_declarator): Pass FRIEND_P to + cp_parser_exception_specification_opt. + (inject_parm_decls): New. + (pop_injected_parms): New. + (cp_parser_class_specifier_1): Implement delayed parsing of + noexcept-specifiers. + (cp_parser_save_noexcept): New. + (cp_parser_late_noexcept_specifier): New. + (noexcept_override_late_checks): New. + (cp_parser_noexcept_specification_opt): Add FRIEND_P parameter. Call + cp_parser_save_noexcept instead of the normal processing if needed. + (cp_parser_exception_specification_opt): Add FRIEND_P parameter and + pass it to cp_parser_noexcept_specification_opt. + (cp_parser_save_member_function_body): Fix comment. + (cp_parser_save_default_args): Maybe save the noexcept-specifier to + post process. + (cp_parser_transaction): Update call to + cp_parser_noexcept_specification_opt. + (cp_parser_transaction_expression): Likewise. + * parser.h (cp_unparsed_functions_entry): Add new field to carry + a noexcept-specifier. + * pt.c (dependent_type_p_r): Handle unparsed noexcept expression. + * search.c (maybe_check_overriding_exception_spec): New function, broken + out of... + (check_final_overrider): ...here. Call + maybe_check_overriding_exception_spec. + * tree.c (canonical_eh_spec): Handle UNPARSED_NOEXCEPT_SPEC_P. + (cp_tree_equal): Handle DEFAULT_ARG. + PR c++/90881 - bogus -Wunused-value in unevaluated context. * cvt.c (convert_to_void): Don't emit unused warnings in an unevaluated context. diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 03c105b..475c584 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -209,7 +209,8 @@ DEFTREECODE (USING_STMT, "using_stmt", tcc_statement, 1) /* An un-parsed default argument. Holds a vector of input tokens and a vector of places where the argument was instantiated before - parsing had occurred. */ + parsing had occurred. This is also used for delayed NSDMIs and + noexcept-specifier parsing. */ DEFTREECODE (DEFAULT_ARG, "default_arg", tcc_exceptional, 0) /* An uninstantiated/unevaluated noexcept-specification. For the diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 98f7a0c..2c05e63 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1190,7 +1190,7 @@ enum cp_identifier_kind { (((struct tree_default_arg *)DEFAULT_ARG_CHECK (NODE))->instantiations) struct GTY (()) tree_default_arg { - struct tree_common common; + struct tree_base base; struct cp_token_cache *tokens; vec<tree, va_gc> *instantiations; }; @@ -1206,6 +1206,9 @@ struct GTY (()) tree_default_arg { #define UNEVALUATED_NOEXCEPT_SPEC_P(NODE) \ (DEFERRED_NOEXCEPT_SPEC_P (NODE) \ && DEFERRED_NOEXCEPT_PATTERN (TREE_PURPOSE (NODE)) == NULL_TREE) +#define UNPARSED_NOEXCEPT_SPEC_P(NODE) \ + ((NODE) && (TREE_PURPOSE (NODE)) \ + && (TREE_CODE (TREE_PURPOSE (NODE)) == DEFAULT_ARG)) struct GTY (()) tree_deferred_noexcept { struct tree_base base; @@ -6467,6 +6470,7 @@ extern bool check_array_designated_initializer (constructor_elt *, unsigned HOST_WIDE_INT); extern bool check_for_uninitialized_const_var (tree, bool, tsubst_flags_t); extern tree build_explicit_specifier (tree, tsubst_flags_t); +extern void do_push_parm_decls (tree, tree, tree *); /* in decl2.c */ extern void record_mangling (tree, bool); @@ -6932,6 +6936,7 @@ extern tree copied_binfo (tree, tree); extern tree original_binfo (tree, tree); extern int shared_member_p (tree); extern bool any_dependent_bases_p (tree = current_nonlambda_class_type ()); +extern bool maybe_check_overriding_exception_spec (tree, tree); /* The representation of a deferred access check. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bcebdc9..8a82c75 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -15761,6 +15761,39 @@ use_eh_spec_block (tree fn) && !DECL_DEFAULTED_FN (fn)); } +/* Helper function to push ARGS into the current lexical scope. DECL + is the function declaration. NONPARMS is used to handle enum + constants. */ + +void +do_push_parm_decls (tree decl, tree args, tree *nonparms) +{ + /* If we're doing semantic analysis, then we'll call pushdecl + for each of these. We must do them in reverse order so that + they end in the correct forward order. */ + args = nreverse (args); + + tree next; + for (tree parm = args; parm; parm = next) + { + next = DECL_CHAIN (parm); + if (TREE_CODE (parm) == PARM_DECL) + pushdecl (parm); + else if (nonparms) + { + /* If we find an enum constant or a type tag, put it aside for + the moment. */ + TREE_CHAIN (parm) = NULL_TREE; + *nonparms = chainon (*nonparms, parm); + } + } + + /* Get the decls in their original chain order and record in the + function. This is all and only the PARM_DECLs that were + pushed into scope by the loop above. */ + DECL_ARGUMENTS (decl) = get_local_decls (); +} + /* Store the parameter declarations into the current function declaration. This is called after parsing the parameter declarations, before digesting the body of the function. @@ -15771,7 +15804,6 @@ static void store_parm_decls (tree current_function_parms) { tree fndecl = current_function_decl; - tree parm; /* This is a chain of any other decls that came in among the parm declarations. If a parm is declared with enum {foo, bar} x; @@ -15786,35 +15818,12 @@ store_parm_decls (tree current_function_parms) and complain if any redundant old-style parm decls were written. */ tree specparms = current_function_parms; - tree next; /* Must clear this because it might contain TYPE_DECLs declared at class level. */ current_binding_level->names = NULL; - /* If we're doing semantic analysis, then we'll call pushdecl - for each of these. We must do them in reverse order so that - they end in the correct forward order. */ - specparms = nreverse (specparms); - - for (parm = specparms; parm; parm = next) - { - next = DECL_CHAIN (parm); - if (TREE_CODE (parm) == PARM_DECL) - pushdecl (parm); - else - { - /* If we find an enum constant or a type tag, - put it aside for the moment. */ - TREE_CHAIN (parm) = NULL_TREE; - nonparms = chainon (nonparms, parm); - } - } - - /* Get the decls in their original chain order and record in the - function. This is all and only the PARM_DECLs that were - pushed into scope by the loop above. */ - DECL_ARGUMENTS (fndecl) = get_local_decls (); + do_push_parm_decls (fndecl, specparms, &nonparms); } else DECL_ARGUMENTS (fndecl) = NULL_TREE; diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 71f5d60..1f87c5a 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1245,6 +1245,7 @@ nothrow_spec_p (const_tree spec) || TREE_VALUE (spec) || spec == noexcept_false_spec || TREE_PURPOSE (spec) == error_mark_node + || UNPARSED_NOEXCEPT_SPEC_P (spec) || processing_template_decl); return false; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 5cbc455..4d4d329 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -247,6 +247,12 @@ static void cp_lexer_stop_debugging static cp_token_cache *cp_token_cache_new (cp_token *, cp_token *); +static tree cp_parser_noexcept_specification_opt + (cp_parser *, bool, bool *, bool, bool); +static tree cp_parser_late_noexcept_specifier + (cp_parser *, tree); +static void noexcept_override_late_checks + (tree, tree); static void cp_parser_initial_pragma (cp_token *); @@ -1974,11 +1980,14 @@ cp_parser_context_new (cp_parser_context* next) parser->unparsed_queues->last ().nsdmis #define unparsed_classes \ parser->unparsed_queues->last ().classes +#define unparsed_noexcepts \ + parser->unparsed_queues->last ().noexcepts static void push_unparsed_function_queues (cp_parser *parser) { - cp_unparsed_functions_entry e = {NULL, make_tree_vector (), NULL, NULL}; + cp_unparsed_functions_entry e = { NULL, make_tree_vector (), NULL, NULL, + NULL }; vec_safe_push (parser->unparsed_queues, e); } @@ -2361,7 +2370,7 @@ static tree cp_parser_exception_declaration static tree cp_parser_throw_expression (cp_parser *); static tree cp_parser_exception_specification_opt - (cp_parser *); + (cp_parser *, bool = false); static tree cp_parser_type_id_list (cp_parser *); @@ -20816,7 +20825,7 @@ cp_parser_direct_declarator (cp_parser* parser, tree tx_qual = cp_parser_tx_qualifier_opt (parser); /* And the exception-specification. */ exception_specification - = cp_parser_exception_specification_opt (parser); + = cp_parser_exception_specification_opt (parser, friend_p); attrs = cp_parser_std_attribute_spec_seq (parser); @@ -23310,6 +23319,34 @@ cp_parser_class_name (cp_parser *parser, return decl; } +/* Make sure that any member-function parameters are in scope. + For instance, a function's noexcept-specifier can use the function's + parameters: + + struct S { + void fn (int p) noexcept(noexcept(p)); + }; + + so we need to make sure name lookup can find them. This is used + when we delay parsing of the noexcept-specifier. */ + +static void +inject_parm_decls (tree decl) +{ + begin_scope (sk_function_parms, decl); + tree args = DECL_ARGUMENTS (decl); + + do_push_parm_decls (decl, args, /*nonparms=*/NULL); +} + +/* Undo the effects of inject_parm_decls. */ + +static void +pop_injected_parms (void) +{ + pop_bindings_and_leave_scope (); +} + /* Parse a class-specifier. class-specifier: @@ -23620,6 +23657,60 @@ cp_parser_class_specifier_1 (cp_parser* parser) vec_safe_truncate (unparsed_classes, 0); after_nsdmi_defaulted_late_checks (type); + /* If there are noexcept-specifiers that have not yet been processed, + take care of them now. */ + class_type = NULL_TREE; + pushed_scope = NULL_TREE; + FOR_EACH_VEC_SAFE_ELT (unparsed_noexcepts, ix, decl) + { + tree ctx = DECL_CONTEXT (decl); + if (class_type != ctx) + { + if (pushed_scope) + pop_scope (pushed_scope); + class_type = ctx; + pushed_scope = push_scope (class_type); + } + + tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)); + spec = TREE_PURPOSE (spec); + + /* Make sure that any template parameters are in scope. */ + maybe_begin_member_template_processing (decl); + + /* Make sure that any member-function parameters are in scope. */ + inject_parm_decls (decl); + + /* 'this' is not allowed in static member functions. */ + unsigned char local_variables_forbidden_p + = parser->local_variables_forbidden_p; + if (DECL_THIS_STATIC (decl)) + parser->local_variables_forbidden_p |= THIS_FORBIDDEN; + + /* 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); + + /* Restore the state of local_variables_forbidden_p. */ + parser->local_variables_forbidden_p = local_variables_forbidden_p; + + /* The finish_struct call above performed various override checking, + but it skipped unparsed noexcept-specifier operands. Now that we + have resolved them, check again. */ + noexcept_override_late_checks (type, decl); + + /* Remove any member-function parameters from the symbol table. */ + pop_injected_parms (); + + /* Remove any template parameters from the symbol table. */ + maybe_end_member_template_processing (); + } + vec_safe_truncate (unparsed_noexcepts, 0); + if (pushed_scope) + pop_scope (pushed_scope); + /* Now parse the body of the functions. */ if (flag_openmp) { @@ -25175,6 +25266,89 @@ cp_parser_base_specifier (cp_parser* parser) /* Exception handling [gram.exception] */ +/* Save the tokens that make up the noexcept-specifier for a member-function. + Returns a DEFAULT_ARG. */ + +static tree +cp_parser_save_noexcept (cp_parser *parser) +{ + cp_token *first = parser->lexer->next_token; + /* We want everything up to, including, the final ')'. */ + cp_parser_cache_group (parser, CPP_CLOSE_PAREN, /*depth=*/0); + cp_token *last = parser->lexer->next_token; + + /* As with default arguments and NSDMIs, make use of DEFAULT_ARG + to carry the information we will need. */ + tree expr = make_node (DEFAULT_ARG); + /* Save away the noexcept-specifier; we will process it when the + class is complete. */ + DEFARG_TOKENS (expr) = cp_token_cache_new (first, last); + expr = build_tree_list (expr, NULL_TREE); + return expr; +} + +/* Used for late processing of noexcept-specifiers of member-functions. + DEFAULT_ARG is the unparsed operand of a noexcept-specifier which + we saved for later; parse it now. */ + +static tree +cp_parser_late_noexcept_specifier (cp_parser *parser, tree default_arg) +{ + /* Make sure we've gotten something that hasn't been parsed yet. */ + gcc_assert (TREE_CODE (default_arg) == DEFAULT_ARG); + + push_unparsed_function_queues (parser); + + /* Push the saved tokens for the noexcept-specifier onto the parser's + lexer stack. */ + cp_token_cache *tokens = DEFARG_TOKENS (default_arg); + cp_parser_push_lexer_for_tokens (parser, tokens); + + /* Parse the cached noexcept-specifier. */ + tree parsed_arg + = cp_parser_noexcept_specification_opt (parser, + /*require_constexpr=*/true, + /*consumed_expr=*/NULL, + /*return_cond=*/false, + /*friend_p=*/false); + + /* Revert to the main lexer. */ + cp_parser_pop_lexer (parser); + + /* Restore the queue. */ + pop_unparsed_function_queues (parser); + + /* And we're done. */ + return parsed_arg; +} + +/* Perform late checking of overriding function with respect to their + noexcept-specifiers. TYPE is the class and FNDECL is the function + that potentially overrides some virtual function with the same + signature. */ + +static void +noexcept_override_late_checks (tree type, tree fndecl) +{ + tree binfo = TYPE_BINFO (type); + tree base_binfo; + + if (DECL_STATIC_FUNCTION_P (fndecl)) + return; + + for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) + { + tree basetype = BINFO_TYPE (base_binfo); + + if (!TYPE_POLYMORPHIC_P (basetype)) + continue; + + tree fn = look_for_overrides_here (basetype, fndecl); + if (fn) + maybe_check_overriding_exception_spec (fndecl, fn); + } +} + /* Parse an (optional) noexcept-specification. noexcept-specification: @@ -25185,13 +25359,15 @@ cp_parser_base_specifier (cp_parser* parser) expression if parentheses follow noexcept, or return BOOLEAN_TRUE_NODE if there are no parentheses. CONSUMED_EXPR will be set accordingly. Otherwise, returns a noexcept specification unless RETURN_COND is true, - in which case a boolean condition is returned instead. */ + in which case a boolean condition is returned instead. If FRIEND_P is true, + the function with this noexcept-specification had the `friend' specifier. */ static tree cp_parser_noexcept_specification_opt (cp_parser* parser, bool require_constexpr, bool* consumed_expr, - bool return_cond) + bool return_cond, + bool friend_p) { cp_token *token; const char *saved_message; @@ -25203,6 +25379,27 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, if (cp_parser_is_keyword (token, RID_NOEXCEPT)) { tree expr; + + /* [class.mem]/6 says that a noexcept-specifer (within the + member-specification of the class) is a complete-class context of + 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) + /* No need to delay parsing for a number literal or true/false. */ + && !literal_p + && at_class_scope_p () + /* Don't delay parsing for friend member functions. */ + && !friend_p + && TYPE_BEING_DEFINED (current_class_type) + && !LAMBDA_TYPE_P (current_class_type)) + return cp_parser_save_noexcept (parser); + cp_lexer_consume_token (parser->lexer); if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) @@ -25273,10 +25470,11 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, throw ( type-id-list [opt] ) Returns a TREE_LIST representing the exception-specification. The - TREE_VALUE of each node is a type. */ + TREE_VALUE of each node is a type. If FRIEND_P is true, the function + with this noexcept-specification had the `friend' specifier. */ static tree -cp_parser_exception_specification_opt (cp_parser* parser) +cp_parser_exception_specification_opt (cp_parser* parser, bool friend_p) { cp_token *token; tree type_id_list; @@ -25286,8 +25484,12 @@ cp_parser_exception_specification_opt (cp_parser* parser) token = cp_lexer_peek_token (parser->lexer); /* Is it a noexcept-specification? */ - type_id_list = cp_parser_noexcept_specification_opt (parser, true, NULL, - false); + type_id_list + = cp_parser_noexcept_specification_opt (parser, + /*require_constexpr=*/true, + /*consumed_expr=*/NULL, + /*return_cond=*/false, + friend_p); if (type_id_list != NULL_TREE) return type_id_list; @@ -28435,7 +28637,7 @@ cp_parser_save_member_function_body (cp_parser* parser, return error_mark_node; } - /* Remember it, if there default args to post process. */ + /* Remember it, if there are default args to post process. */ cp_parser_save_default_args (parser, fn); /* Save away the tokens that make up the body of the @@ -28728,6 +28930,11 @@ cp_parser_save_default_args (cp_parser* parser, tree decl) vec_safe_push (unparsed_funs_with_default_args, entry); break; } + + /* Remember if there is a noexcept-specifier to post process. */ + tree spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)); + if (UNPARSED_NOEXCEPT_SPEC_P (spec)) + vec_safe_push (unparsed_noexcepts, decl); } /* DEFAULT_ARG contains the saved tokens for the initializer of DECL, @@ -40599,7 +40806,11 @@ cp_parser_transaction (cp_parser *parser, cp_token *token) noex = NULL_TREE; } else - noex = cp_parser_noexcept_specification_opt (parser, true, NULL, true); + noex = cp_parser_noexcept_specification_opt (parser, + /*require_constexpr=*/true, + /*consumed_expr=*/NULL, + /*return_cond=*/true, + /*friend_p=*/false); /* Keep track if we're in the lexical scope of an outer transaction. */ new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); @@ -40659,8 +40870,11 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword) parser->in_transaction = this_in; /* Parse a noexcept specification. */ - noex = cp_parser_noexcept_specification_opt (parser, false, &noex_expr, - true); + noex = cp_parser_noexcept_specification_opt (parser, + /*require_constexpr=*/false, + &noex_expr, + /*return_cond=*/true, + /*friend_p=*/false); if (!noex || !noex_expr || cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index c03a9d8..2890788 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -166,6 +166,9 @@ struct GTY(()) cp_unparsed_functions_entry { /* Nested classes go in this vector, so that we can do some final processing after parsing any NSDMIs. */ vec<tree, va_gc> *classes; + + /* Functions with noexcept-specifiers that require post-processing. */ + vec<tree, va_gc> *noexcepts; }; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 69de553..fb89b93 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -25313,8 +25313,9 @@ dependent_type_p_r (tree type) if (tree noex = TREE_PURPOSE (spec)) /* Treat DEFERRED_NOEXCEPT as non-dependent, since it doesn't affect overload resolution and treating it as dependent breaks - things. */ + things. Same for an unparsed noexcept expression. */ if (TREE_CODE (noex) != DEFERRED_NOEXCEPT + && TREE_CODE (noex) != DEFAULT_ARG && value_dependent_expression_p (noex)) return true; return false; diff --git a/gcc/cp/search.c b/gcc/cp/search.c index dac08d4..372c442 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1860,6 +1860,39 @@ locate_field_accessor (tree basetype_path, tree field_decl, bool const_p) NULL, &lfd); } +/* Check throw specifier of OVERRIDER is at least as strict as + the one of BASEFN. */ + +bool +maybe_check_overriding_exception_spec (tree overrider, tree basefn) +{ + maybe_instantiate_noexcept (basefn); + maybe_instantiate_noexcept (overrider); + tree base_throw = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (basefn)); + tree over_throw = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (overrider)); + + if (DECL_INVALID_OVERRIDER_P (overrider)) + return true; + + /* Can't check this yet. Pretend this is fine and let + noexcept_override_late_checks check this later. */ + if (UNPARSED_NOEXCEPT_SPEC_P (base_throw) + || UNPARSED_NOEXCEPT_SPEC_P (over_throw)) + return true; + + if (!comp_except_specs (base_throw, over_throw, ce_derived)) + { + auto_diagnostic_group d; + error ("looser exception specification on overriding virtual function " + "%q+#F", overrider); + inform (DECL_SOURCE_LOCATION (basefn), + "overridden function is %q#F", basefn); + DECL_INVALID_OVERRIDER_P (overrider) = 1; + return false; + } + return true; +} + /* Check that virtual overrider OVERRIDER is acceptable for base function BASEFN. Issue diagnostic, and return zero, if unacceptable. */ @@ -1870,7 +1903,6 @@ check_final_overrider (tree overrider, tree basefn) tree base_type = TREE_TYPE (basefn); tree over_return = fndecl_declared_return_type (overrider); tree base_return = fndecl_declared_return_type (basefn); - tree over_throw, base_throw; int fail = 0; @@ -1954,21 +1986,8 @@ check_final_overrider (tree overrider, tree basefn) return 0; } - /* Check throw specifier is at least as strict. */ - maybe_instantiate_noexcept (basefn); - maybe_instantiate_noexcept (overrider); - base_throw = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (basefn)); - over_throw = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (overrider)); - - if (!comp_except_specs (base_throw, over_throw, ce_derived)) - { - auto_diagnostic_group d; - error ("looser throw specifier for %q+#F", overrider); - inform (DECL_SOURCE_LOCATION (basefn), - "overridden function is %q#F", basefn); - DECL_INVALID_OVERRIDER_P (overrider) = 1; - return 0; - } + if (!maybe_check_overriding_exception_spec (overrider, basefn)) + return 0; /* Check for conflicting type attributes. But leave transaction_safe for set_one_vmethod_tm_attributes. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 978aea5..ebfe362 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2546,6 +2546,7 @@ canonical_eh_spec (tree raises) if (raises == NULL_TREE) return raises; else if (DEFERRED_NOEXCEPT_SPEC_P (raises) + || UNPARSED_NOEXCEPT_SPEC_P (raises) || uses_template_parms (raises) || uses_template_parms (TREE_PURPOSE (raises))) /* Keep a dependent or deferred exception specification. */ @@ -3656,6 +3657,7 @@ cp_tree_equal (tree t1, tree t2) case IDENTIFIER_NODE: case SSA_NAME: case USING_DECL: + case DEFAULT_ARG: return false; case BASELINK: |