... I understand that at this point likely this isn't 4.9 material anymore.

Just wanted to add that in the meanwhile I noticed that my WIP patch fixes c++/56037 too, which in fact seems to me a slightly less uncommon kind of code and that I tidied a bit the comments and simplified the cp_parser_cast_expression hunk.

Still looking for feedback, in any case!

Thanks!
Paolo.

///////////////////
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 204268)
+++ cp/parser.c (working copy)
@@ -5800,31 +5800,45 @@ cp_parser_postfix_expression (cp_parser *parser, b
            && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
          {
            tree initializer = NULL_TREE;
-           bool saved_in_type_id_in_expr_p;
+           bool compound_literal_p;
 
            cp_parser_parse_tentatively (parser);
            /* Consume the `('.  */
            cp_lexer_consume_token (parser->lexer);
-           /* Parse the type.  */
-           saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
-           parser->in_type_id_in_expr_p = true;
-           type = cp_parser_type_id (parser);
-           parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
-           /* Look for the `)'.  */
-           cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+
+           /* Avoid calling cp_parser_type_id pointlessly, see comment
+              in cp_parser_cast_expression about c++/29234.  */
+           cp_lexer_save_tokens (parser->lexer);
+
+           compound_literal_p
+             = (cp_parser_skip_to_closing_parenthesis (parser, false, false,
+                                                       /*consume_paren=*/true)
+                && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE));
+
+           /* Roll back the tokens we skipped.  */
+           cp_lexer_rollback_tokens (parser->lexer);
+
+           if (!compound_literal_p)
+             cp_parser_simulate_error (parser);
+           else
+             {
+               /* Parse the type.  */
+               bool saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
+               parser->in_type_id_in_expr_p = true;
+               type = cp_parser_type_id (parser);
+               parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
+               /* Look for the `)'.  */
+               cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+             }
+
            /* If things aren't going well, there's no need to
               keep going.  */
            if (!cp_parser_error_occurred (parser))
              {
-               if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
-                 {
-                   bool non_constant_p;
-                   /* Parse the brace-enclosed initializer list.  */
-                   initializer = cp_parser_braced_list (parser,
-                                                        &non_constant_p);
-                 }
-               else
-                 cp_parser_simulate_error (parser);
+               bool non_constant_p;
+               /* Parse the brace-enclosed initializer list.  */
+               initializer = cp_parser_braced_list (parser,
+                                                    &non_constant_p);
              }
            /* If that worked, we're definitely looking at a
               compound-literal expression.  */
@@ -7492,6 +7506,7 @@ cp_parser_tokens_start_cast_expression (cp_parser
     case CPP_CLOSE_SQUARE:
     case CPP_CLOSE_PAREN:
     case CPP_CLOSE_BRACE:
+    case CPP_OPEN_BRACE:
     case CPP_DOT:
     case CPP_DOT_STAR:
     case CPP_DEREF:
@@ -7559,7 +7574,7 @@ cp_parser_cast_expression (cp_parser *parser, bool
     {
       tree type = NULL_TREE;
       tree expr = NULL_TREE;
-      bool compound_literal_p;
+      bool cast_expression_p;
       const char *saved_message;
 
       /* There's no way to know yet whether or not this is a cast.
@@ -7582,26 +7597,38 @@ cp_parser_cast_expression (cp_parser *parser, bool
         will commit to the parse at that point, because we cannot
         undo the action that is done when creating a new class.  So,
         then we cannot back up and do a postfix-expression.
+        Another tricky case is the following (c++/29234):
 
+         struct S { void operator () (); };
+
+         void foo ()
+         {
+           ( S()() );
+         }
+
+        As a type-id we parse the parenthesized S()() as a function
+        returning a function, groktypename complains and we cannot
+        back up in this case too.
+
         Therefore, we scan ahead to the closing `)', and check to see
-        if the token after the `)' is a `{'.  If so, we are not
-        looking at a cast-expression.
+        if the tokens after the `)' can start a cast-expression.  Otherwise
+        we are dealing with an unary-expression, a postfix-expression
+        or something else.
 
         Save tokens so that we can put them back.  */
       cp_lexer_save_tokens (parser->lexer);
-      /* Skip tokens until the next token is a closing parenthesis.
-        If we find the closing `)', and the next token is a `{', then
-        we are looking at a compound-literal.  */
-      compound_literal_p
+
+      /* We may be looking at a cast-expression.  */
+      cast_expression_p
        = (cp_parser_skip_to_closing_parenthesis (parser, false, false,
                                                  /*consume_paren=*/true)
-          && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE));
+          && cp_parser_tokens_start_cast_expression (parser));
+
       /* Roll back the tokens we skipped.  */
       cp_lexer_rollback_tokens (parser->lexer);
-      /* If we were looking at a compound-literal, simulate an error
-        so that the call to cp_parser_parse_definitely below will
-        fail.  */
-      if (compound_literal_p)
+      /* If we aren't looking at a cast-expression, simulate an error so
+        that the call to cp_parser_parse_definitely below will fail.  */
+      if (!cast_expression_p)
        cp_parser_simulate_error (parser);
       else
        {
@@ -7620,8 +7647,7 @@ cp_parser_cast_expression (cp_parser *parser, bool
       /* At this point this can only be either a cast or a
         parenthesized ctor such as `(T ())' that looks like a cast to
         function returning T.  */
-      if (!cp_parser_error_occurred (parser)
-         && cp_parser_tokens_start_cast_expression (parser))
+      if (!cp_parser_error_occurred (parser))
        {
          cp_parser_parse_definitely (parser);
          expr = cp_parser_cast_expression (parser,
Index: testsuite/g++.dg/parse/pr29234.C
===================================================================
--- testsuite/g++.dg/parse/pr29234.C    (revision 0)
+++ testsuite/g++.dg/parse/pr29234.C    (working copy)
@@ -0,0 +1,16 @@
+// PR c++/29234
+
+struct S { void operator()(); };
+
+void foo ()
+{
+  ( S()() );
+}
+
+struct C { void operator[](C); };
+
+void bar ()
+{
+  C x;
+  ( C()[x] );
+}
Index: testsuite/g++.dg/parse/pr56037.C
===================================================================
--- testsuite/g++.dg/parse/pr56037.C    (revision 0)
+++ testsuite/g++.dg/parse/pr56037.C    (working copy)
@@ -0,0 +1,12 @@
+// PR c++/56037
+
+struct T
+{
+  T(int, int);
+};
+
+int main()
+{
+  static const int zero = 0;
+  (T(int(zero), int(zero)));
+}

Reply via email to