mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-21 15:31:09 +08:00
c++: most vexing parse and braced CTAD [PR89062]
Here grokdeclarator is emitting the error error: class template placeholder ‘Foo’ not permitted in this context during the tentative (and ultimately futile) parse of 'x' as a function declaration. This happens because when parsing 'Foo{1}', cp_parser_parameter_declaration yields a parameter declaration with no declarator and whose type is a CTAD placeholder, and stops short of consuming the '{'. The caller cp_parser_parameter_declaration_list then calls grokdeclarator on this declarator, hence the error, and soon thereafter we abort this tentative parse since the next token '{' doesn't make sense in the context of a parameter list. Note that we don't have this issue with parenthesized CTAD Foo<int> x(Foo(1)); because in this case cp_parser_direct_declarator (called indirectly from c_p_p_d) consumes the '(' and returns cp_error_declarator instead of a NULL declarator (and also simulates a parse error), and grokdeclarator exits early for this declarator without emitting any error. Since grokdeclarator doesn't take a 'complain' parameter, to fix this we need to avoid calling grokdeclarator in this situation. To that end this patch makes c_p_p_d simulate an error when a construct is a CTAD expression and definitely not a parameter declaration, so that c_p_p_d_l can avoid calling grokdeclarator by checking for this simulated error. Alternatively we could keep all this logic inside c_p_p_d_l and not touch c_p_p_d at all, but this approach seems slightly less adhoc. PR c++/89062 gcc/cp/ChangeLog: * parser.c (cp_parser_parameter_declaration_list): Don't call grokdeclarator if cp_parser_error_occurred. (cp_parser_parameter_declaration): Simulate an error if we see the beginning of a CTAD form, i.e. if we see an opening brace after the decl-specifier-seq and the type is a CTAD placeholder. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction97.C: New test.
This commit is contained in:
parent
4fa6c0ec35
commit
6186708312
@ -24284,7 +24284,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags)
|
||||
and warn in grokparms if appropriate. */
|
||||
deprecated_state = DEPRECATED_SUPPRESS;
|
||||
|
||||
if (parameter)
|
||||
if (parameter && !cp_parser_error_occurred (parser))
|
||||
{
|
||||
decl = grokdeclarator (parameter->declarator,
|
||||
¶meter->decl_specifiers,
|
||||
@ -24499,7 +24499,7 @@ cp_parser_parameter_declaration (cp_parser *parser,
|
||||
parser->default_arg_ok_p = false;
|
||||
|
||||
/* After seeing a decl-specifier-seq, if the next token is not a
|
||||
"(", there is no possibility that the code is a valid
|
||||
"(" or "{", there is no possibility that the code is a valid
|
||||
expression. Therefore, if parsing tentatively, we commit at
|
||||
this point. */
|
||||
if (!parser->in_template_argument_list_p
|
||||
@ -24512,9 +24512,18 @@ cp_parser_parameter_declaration (cp_parser *parser,
|
||||
of some object of type "char" to "int". */
|
||||
&& !parser->in_type_id_in_expr_p
|
||||
&& cp_parser_uncommitted_to_tentative_parse_p (parser)
|
||||
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
|
||||
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
|
||||
cp_parser_commit_to_tentative_parse (parser);
|
||||
{
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
|
||||
{
|
||||
if (decl_specifiers.type
|
||||
&& template_placeholder_p (decl_specifiers.type))
|
||||
/* This is a CTAD expression, not a parameter declaration. */
|
||||
cp_parser_simulate_error (parser);
|
||||
}
|
||||
else
|
||||
cp_parser_commit_to_tentative_parse (parser);
|
||||
}
|
||||
/* Parse the declarator. */
|
||||
declarator_token_start = token;
|
||||
declarator = cp_parser_declarator (parser,
|
||||
|
6
gcc/testsuite/g++.dg/cpp1z/class-deduction97.C
Normal file
6
gcc/testsuite/g++.dg/cpp1z/class-deduction97.C
Normal file
@ -0,0 +1,6 @@
|
||||
// PR c++/89062
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
template<class T> struct Foo { Foo(T); };
|
||||
|
||||
Foo<int> x(Foo{1});
|
Loading…
x
Reference in New Issue
Block a user