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