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 an 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 when using only parentheses Foo<int> x(Foo(1)); because in this case cp_parser_direct_declarator (called indirectly from c_p_p_d) instead consumes the '(' and returns a cp_error_declarator rather than 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 if an error has been simulated. 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. On the other hand, it seems weird that cp_parser_direct_declarator (with flags=CP_PARSER_DECLARATOR_EITHER) returns cp_error_declarator for 'Foo(1)' (and consumes the '(') but NULL for 'Foo{1}' (and doesn't consume the '{'), and perhaps this issue could fixed by returning cp_error_declarator in the latter case as well, but I didn't try this approach. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? 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 gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction97.C: New test. --- gcc/cp/parser.c | 17 +++++++++++++---- gcc/testsuite/g++.dg/cpp1z/class-deduction97.C | 6 ++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction97.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8b551db2c8a..d4da25ca703 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -24061,7 +24061,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, @@ -24276,7 +24276,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 @@ -24289,9 +24289,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, diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C new file mode 100644 index 00000000000..32818681d8f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C @@ -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}); -- 2.33.0.rc1