Patchwork [C++,/,RFC] PR 29234

login
register
mail settings
Submitter Paolo Carlini
Date Oct. 31, 2013, 7:07 p.m.
Message ID <5272AA81.9070308@oracle.com>
Download mbox | patch
Permalink /patch/287587/
State New
Headers show

Comments

Paolo Carlini - Oct. 31, 2013, 7:07 p.m.
... 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.

///////////////////
Jason Merrill - Nov. 1, 2013, 5:52 p.m.
On 10/31/2013 03:07 PM, Paolo Carlini wrote:
> ... I understand that at this point likely this isn't 4.9 material anymore.

I think it's fine for 4.9, we're still in stage 1.

The revised patch is OK.

Jason

Patch

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)));
+}