On 8/9/21 1:15 PM, Patrick Palka wrote:
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.

From the comment, this seems to be because ObjC++ allows { at the end of the parameter-declaration-list. No idea what that would mean.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

OK.

        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,
                                 &parameter->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});


Reply via email to