From 17adeaa773a12d1fc04b1af28aadd9c255ae56d0 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Mon, 30 Jun 2014 18:30:50 +0000 Subject: [PATCH] re PR c++/54891 ([C++11] lambda-expression and explicit type conversion (cast notation)) /cp 2014-06-30 Paolo Carlini PR c++/54891 * parser.c (cp_parser_tokens_start_cast_expression): In C++11 a '[' can also start a primary-expression. (cp_parser_cast_expression): Parse a cast-expression only tentatively when cp_parser_tokens_start_cast_expression returns -1. /testsuite 2014-06-30 Paolo Carlini PR c++/54891 * g++.dg/cpp0x/lambda/lambda-cast1.C: New. From-SVN: r212162 --- gcc/cp/ChangeLog | 8 +++ gcc/cp/parser.c | 82 +++++++++++++++--------- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/cpp0x/lambda/lambda-cast1.C | 7 ++ 4 files changed, 72 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-cast1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f121236..bfe4da6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2014-06-30 Paolo Carlini + + PR c++/54891 + * parser.c (cp_parser_tokens_start_cast_expression): In C++11 + a '[' can also start a primary-expression. + (cp_parser_cast_expression): Parse a cast-expression only tentatively + when cp_parser_tokens_start_cast_expression returns -1. + 2014-06-30 Jason Merrill PR c++/61539 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 057b6ca..013fc6e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4109,6 +4109,7 @@ complain_flags (bool decltype_p) this ( expression ) id-expression + lambda-expression (C++11) GNU Extensions: @@ -7621,10 +7622,10 @@ cp_parser_delete_expression (cp_parser* parser) tf_warning_or_error); } -/* Returns true if TOKEN may start a cast-expression and false - otherwise. */ +/* Returns 1 if TOKEN may start a cast-expression and, in C++11, + isn't '[', -1 if TOKEN is '[' in C++11, 0 otherwise. */ -static bool +static int cp_parser_tokens_start_cast_expression (cp_parser *parser) { cp_token *token = cp_lexer_peek_token (parser->lexer); @@ -7667,7 +7668,7 @@ cp_parser_tokens_start_cast_expression (cp_parser *parser) case CPP_OR: case CPP_OR_OR: case CPP_EOF: - return false; + return 0; case CPP_OPEN_PAREN: /* In ((type ()) () the last () isn't a valid cast-expression, @@ -7675,12 +7676,15 @@ cp_parser_tokens_start_cast_expression (cp_parser *parser) return cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_CLOSE_PAREN; - /* '[' may start a primary-expression in obj-c++. */ + /* '[' may start a primary-expression in obj-c++ and in C++11, + as a lambda-expression, eg, '(void)[]{}'. */ case CPP_OPEN_SQUARE: + if (cxx_dialect >= cxx11) + return -1; return c_dialect_objc (); default: - return true; + return 1; } } @@ -7705,7 +7709,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, { tree type = NULL_TREE; tree expr = NULL_TREE; - bool cast_expression_p; + int cast_expression = 0; const char *saved_message; /* There's no way to know yet whether or not this is a cast. @@ -7728,6 +7732,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, 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 () (); }; @@ -7746,20 +7751,30 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, we are dealing with an unary-expression, a postfix-expression or something else. + Yet another tricky case, in C++11, is the following (c++/54891): + + (void)[]{}; + + The issue is that usually, besides the case of lambda-expressions, + the parenthesized type-id cannot be followed by '[', and, eg, we + want to parse '(C ())[2];' in parse/pr26997.C as unary-expression. + Thus, if cp_parser_tokens_start_cast_expression returns -1, below + we don't commit, we try a cast-expression, then an unary-expression. + Save tokens so that we can put them back. */ cp_lexer_save_tokens (parser->lexer); /* We may be looking at a cast-expression. */ - cast_expression_p - = (cp_parser_skip_to_closing_parenthesis (parser, false, false, - /*consume_paren=*/true) - && cp_parser_tokens_start_cast_expression (parser)); + if (cp_parser_skip_to_closing_parenthesis (parser, false, false, + /*consume_paren=*/true)) + cast_expression + = cp_parser_tokens_start_cast_expression (parser); /* Roll back the tokens we skipped. */ cp_lexer_rollback_tokens (parser->lexer); /* 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) + that the call to cp_parser_error_occurred below returns true. */ + if (!cast_expression) cp_parser_simulate_error (parser); else { @@ -7780,30 +7795,37 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, function returning T. */ if (!cp_parser_error_occurred (parser)) { - cp_parser_parse_definitely (parser); + /* Only commit if the cast-expression doesn't start with '[' in + C++11, which may or may not start a lambda-expression. */ + if (cast_expression > 0) + cp_parser_commit_to_topmost_tentative_parse (parser); + expr = cp_parser_cast_expression (parser, /*address_p=*/false, /*cast_p=*/true, /*decltype_p=*/false, pidk); - /* Warn about old-style casts, if so requested. */ - if (warn_old_style_cast - && !in_system_header_at (input_location) - && !VOID_TYPE_P (type) - && current_lang_name != lang_name_c) - warning (OPT_Wold_style_cast, "use of old-style cast"); - - /* Only type conversions to integral or enumeration types - can be used in constant-expressions. */ - if (!cast_valid_in_integral_constant_expression_p (type) - && cp_parser_non_integral_constant_expression (parser, - NIC_CAST)) - return error_mark_node; + if (cp_parser_parse_definitely (parser)) + { + /* Warn about old-style casts, if so requested. */ + if (warn_old_style_cast + && !in_system_header_at (input_location) + && !VOID_TYPE_P (type) + && current_lang_name != lang_name_c) + warning (OPT_Wold_style_cast, "use of old-style cast"); + + /* Only type conversions to integral or enumeration types + can be used in constant-expressions. */ + if (!cast_valid_in_integral_constant_expression_p (type) + && cp_parser_non_integral_constant_expression (parser, + NIC_CAST)) + return error_mark_node; - /* Perform the cast. */ - expr = build_c_cast (input_location, type, expr); - return expr; + /* Perform the cast. */ + expr = build_c_cast (input_location, type, expr); + return expr; + } } else cp_parser_abort_tentative_parse (parser); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 930d60b..abfe481 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2014-06-30 Paolo Carlini + PR c++/54891 + * g++.dg/cpp0x/lambda/lambda-cast1.C: New. + +2014-06-30 Paolo Carlini + PR c++/51400 * g++.dg/cpp0x/constexpr-attribute3.C: New. diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-cast1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-cast1.C new file mode 100644 index 0000000..e5d49ca --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-cast1.C @@ -0,0 +1,7 @@ +// PR c++/54891 +// { dg-do compile { target c++11 } } + +int main() +{ + (void)[]{}; +} -- 2.7.4