From f981395c220c9afd73be138294946e085e64af78 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 11 May 2020 15:39:44 -0400 Subject: [PATCH] c++: Use of 'this' in parameter declaration [PR90748] We were incorrectly accepting the use of 'this' at parse time and then crashing when we tried to instantiate it. It is invalid because 'this' is not in scope until after the function-cv-quals. So let's hoist setting current_class_ptr up from cp_parser_late_return_type_opt into cp_parser_direct_declarator where it can work for noexcept as well. gcc/cp/ChangeLog 2020-05-11 Jason Merrill PR c++/90748 * parser.c (inject_parm_decls): Set current_class_ptr here. (cp_parser_direct_declarator): And here. (cp_parser_late_return_type_opt): Not here. (cp_parser_noexcept_specification_opt): Nor here. (cp_parser_exception_specification_opt) (cp_parser_late_noexcept_specifier): Remove unneeded parameters. --- gcc/cp/ChangeLog | 10 +++ gcc/cp/parser.c | 87 ++++++++++--------------- gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 10 +++ 3 files changed, 56 insertions(+), 51 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept59.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2cc9b8deb15..3f135064887 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2020-05-11 Jason Merrill + + PR c++/90748 + * parser.c (inject_parm_decls): Set current_class_ptr here. + (cp_parser_direct_declarator): And here. + (cp_parser_late_return_type_opt): Not here. + (cp_parser_noexcept_specification_opt): Nor here. + (cp_parser_exception_specification_opt) + (cp_parser_late_noexcept_specifier): Remove unneeded parameters. + 2020-05-11 Jason Merrill * decl.c (cxx_init_decl_processing): Call declare_weak for diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 591f44f4934..10627cb1c92 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -246,7 +246,7 @@ static void cp_lexer_stop_debugging static cp_token_cache *cp_token_cache_new (cp_token *, cp_token *); static tree cp_parser_late_noexcept_specifier - (cp_parser *, tree, tree); + (cp_parser *, tree); static void noexcept_override_late_checks (tree, tree); @@ -2246,7 +2246,7 @@ static cp_ref_qualifier cp_parser_ref_qualifier_opt static tree cp_parser_tx_qualifier_opt (cp_parser *); static tree cp_parser_late_return_type_opt - (cp_parser *, cp_declarator *, tree &, cp_cv_quals); + (cp_parser *, cp_declarator *, tree &); static tree cp_parser_declarator_id (cp_parser *, bool); static tree cp_parser_type_id @@ -2385,11 +2385,11 @@ 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_flags, cp_cv_quals); + (cp_parser *, cp_parser_flags); static tree cp_parser_type_id_list (cp_parser *); static tree cp_parser_noexcept_specification_opt - (cp_parser *, cp_parser_flags, bool, bool *, bool, cp_cv_quals); + (cp_parser *, cp_parser_flags, bool, bool *, bool); /* GNU Extensions */ @@ -11082,8 +11082,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) /* Parse optional exception specification. */ exception_spec - = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE, - quals); + = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE); std_attrs = cp_parser_std_attribute_spec_seq (parser); @@ -21227,11 +21226,17 @@ cp_parser_direct_declarator (cp_parser* parser, ref_qual = cp_parser_ref_qualifier_opt (parser); /* Parse the tx-qualifier. */ tree tx_qual = cp_parser_tx_qualifier_opt (parser); - /* And the exception-specification. */ + + tree save_ccp = current_class_ptr; + tree save_ccr = current_class_ref; + if (memfn) + /* DR 1207: 'this' is in scope after the cv-quals. */ + inject_this_parameter (current_class_type, cv_quals); + + /* Parse the exception-specification. */ exception_specification = cp_parser_exception_specification_opt (parser, - flags, - cv_quals); + flags); attrs = cp_parser_std_attribute_spec_seq (parser); @@ -21241,8 +21246,7 @@ cp_parser_direct_declarator (cp_parser* parser, tree gnu_attrs = NULL_TREE; tree requires_clause = NULL_TREE; late_return = (cp_parser_late_return_type_opt - (parser, declarator, requires_clause, - memfn ? cv_quals : -1)); + (parser, declarator, requires_clause)); /* Parse the virt-specifier-seq. */ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); @@ -21264,6 +21268,9 @@ cp_parser_direct_declarator (cp_parser* parser, function. */ parser->default_arg_ok_p = false; + current_class_ptr = save_ccp; + current_class_ref = save_ccr; + /* Restore the state of local_variables_forbidden_p. */ parser->local_variables_forbidden_p = local_variables_forbidden_p; @@ -22077,7 +22084,7 @@ parsing_nsdmi (void) static tree cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator, - tree& requires_clause, cp_cv_quals quals) + tree& requires_clause) { cp_token *token; tree type = NULL_TREE; @@ -22099,14 +22106,6 @@ cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator, && !(declare_simd_p || oacc_routine_p)) return NULL_TREE; - tree save_ccp = current_class_ptr; - tree save_ccr = current_class_ref; - if (quals >= 0) - { - /* DR 1207: 'this' is in scope in the trailing return type. */ - inject_this_parameter (current_class_type, quals); - } - if (token->type == CPP_DEREF) { /* Consume the ->. */ @@ -22128,12 +22127,6 @@ cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator, = cp_parser_late_parsing_oacc_routine (parser, declarator->attributes); - if (quals >= 0) - { - current_class_ptr = save_ccp; - current_class_ref = save_ccr; - } - return type; } @@ -23782,6 +23775,14 @@ inject_parm_decls (tree decl) tree args = DECL_ARGUMENTS (decl); do_push_parm_decls (decl, args, /*nonparms=*/NULL); + + if (args && is_this_parameter (args)) + { + gcc_checking_assert (current_class_ptr == NULL_TREE); + current_class_ptr = NULL_TREE; + current_class_ref = cp_build_fold_indirect_ref (args); + current_class_ptr = args; + } } /* Undo the effects of inject_parm_decls. */ @@ -23790,6 +23791,7 @@ static void pop_injected_parms (void) { pop_bindings_and_leave_scope (); + current_class_ptr = current_class_ref = NULL_TREE; } /* Parse a class-specifier. @@ -24131,7 +24133,7 @@ cp_parser_class_specifier_1 (cp_parser* parser) parser->local_variables_forbidden_p |= THIS_FORBIDDEN; /* Now we can parse the noexcept-specifier. */ - spec = cp_parser_late_noexcept_specifier (parser, spec, decl); + spec = cp_parser_late_noexcept_specifier (parser, spec); if (spec != error_mark_node) TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec); @@ -25762,8 +25764,7 @@ cp_parser_save_noexcept (cp_parser *parser) member function. */ static tree -cp_parser_late_noexcept_specifier (cp_parser *parser, tree default_arg, - tree decl) +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) == DEFERRED_PARSE); @@ -25775,16 +25776,13 @@ cp_parser_late_noexcept_specifier (cp_parser *parser, tree default_arg, cp_token_cache *tokens = DEFPARSE_TOKENS (default_arg); cp_parser_push_lexer_for_tokens (parser, tokens); - /* We need to know if this member function was declared `const'. Look - at the this parameter to figure that out. */ - cp_cv_quals quals = type_memfn_quals (TREE_TYPE (decl)); /* Parse the cached noexcept-specifier. */ tree parsed_arg = cp_parser_noexcept_specification_opt (parser, CP_PARSER_FLAGS_NONE, /*require_constexpr=*/true, /*consumed_expr=*/NULL, - /*return_cond=*/false, quals); + /*return_cond=*/false); /* Revert to the main lexer. */ cp_parser_pop_lexer (parser); @@ -25842,8 +25840,7 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, cp_parser_flags flags, bool require_constexpr, bool* consumed_expr, - bool return_cond, - cp_cv_quals quals) + bool return_cond) { cp_token *token; const char *saved_message; @@ -25885,12 +25882,6 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, matching_parens parens; parens.consume_open (parser); - tree save_ccp = current_class_ptr; - tree save_ccr = current_class_ref; - - if (current_class_type) - inject_this_parameter (current_class_type, quals); - if (require_constexpr) { /* Types may not be defined in an exception-specification. */ @@ -25920,9 +25911,6 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, } parens.require_close (parser); - - current_class_ptr = save_ccp; - current_class_ref = save_ccr; } else { @@ -25954,8 +25942,7 @@ cp_parser_noexcept_specification_opt (cp_parser* parser, static tree cp_parser_exception_specification_opt (cp_parser* parser, - cp_parser_flags flags, - cp_cv_quals quals) + cp_parser_flags flags) { cp_token *token; tree type_id_list; @@ -25969,7 +25956,7 @@ cp_parser_exception_specification_opt (cp_parser* parser, = cp_parser_noexcept_specification_opt (parser, flags, /*require_constexpr=*/true, /*consumed_expr=*/NULL, - /*return_cond=*/false, quals); + /*return_cond=*/false); if (type_id_list != NULL_TREE) return type_id_list; @@ -43293,8 +43280,7 @@ cp_parser_transaction (cp_parser *parser, cp_token *token) CP_PARSER_FLAGS_NONE, /*require_constexpr=*/true, /*consumed_expr=*/NULL, - /*return_cond=*/true, - TYPE_UNQUALIFIED); + /*return_cond=*/true); /* Keep track if we're in the lexical scope of an outer transaction. */ new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); @@ -43358,8 +43344,7 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword) CP_PARSER_FLAGS_NONE, /*require_constexpr=*/false, &noex_expr, - /*return_cond=*/true, - TYPE_UNQUALIFIED); + /*return_cond=*/true); if (!noex || !noex_expr || cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C new file mode 100644 index 00000000000..c752601ba09 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C @@ -0,0 +1,10 @@ +// PR c++/90748 +// { dg-do compile { target c++11 } } + +template class A +{ + void e (); + bool f (int() noexcept(this->e())); // { dg-error "this" } + bool g (int() noexcept(e())); // { dg-error "without object" } +}; +A<> b; -- 2.30.2