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  <jason@redhat.com>

	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.
This commit is contained in:
Jason Merrill 2020-05-11 15:39:44 -04:00
parent 1422c2e446
commit f981395c22
3 changed files with 56 additions and 51 deletions

View file

@ -1,3 +1,13 @@
2020-05-11 Jason Merrill <jason@redhat.com>
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 <jason@redhat.com>
* decl.c (cxx_init_decl_processing): Call declare_weak for

View file

@ -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)

View file

@ -0,0 +1,10 @@
// PR c++/90748
// { dg-do compile { target c++11 } }
template <class ...Ts> class A
{
void e ();
bool f (int() noexcept(this->e())); // { dg-error "this" }
bool g (int() noexcept(e())); // { dg-error "without object" }
};
A<> b;