aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2014-10-15 10:12:24 -0400
committerJason Merrill <jason@gcc.gnu.org>2014-10-15 10:12:24 -0400
commit5f83e90bb6f44cb079edf65b55f3caab34c42516 (patch)
treed4540d6292cb29ad0a829b9d951b84d6a3058e85 /gcc
parent327a79a52392f9fec4c92693278fe8d362bc7008 (diff)
downloadgcc-5f83e90bb6f44cb079edf65b55f3caab34c42516.zip
gcc-5f83e90bb6f44cb079edf65b55f3caab34c42516.tar.gz
gcc-5f83e90bb6f44cb079edf65b55f3caab34c42516.tar.bz2
re PR c++/63455 (decltype of statement expression internal compiler error: in cp_parser_abort_tentative_parse, at cp/parser.c:25062)
PR c++/63455 c-family/ * c-common.h (CPP_PREPARSED_EXPR): New. (N_CP_TTYPES): Adjust. cp/ * parser.c (struct saved_token_sentinel): New. (cp_parser_statement): Use it. (cp_parser_start_tentative_firewall): New. (cp_parser_end_tentative_firewall): New. (cp_parser_lambda_expression): Use them. (cp_parser_statement_expr): New. (cp_parser_primary_expression): Use it. From-SVN: r216260
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c-family/ChangeLog6
-rw-r--r--gcc/c-family/c-common.h5
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/parser.c213
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-sfinae1.C9
-rw-r--r--gcc/testsuite/g++.dg/ext/stmtexpr16.C10
6 files changed, 194 insertions, 60 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 056a0d5..7c51528 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2014-10-14 Jason Merrill <jason@redhat.com>
+
+ PR c++/63455
+ * c-common.h (CPP_PREPARSED_EXPR): New.
+ (N_CP_TTYPES): Adjust.
+
2014-10-15 Marek Polacek <polacek@redhat.com>
* c-opts.c (c_common_init_options): Make -std=gnu11 the default for C.
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index fec9a06..b45ccfc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -361,8 +361,11 @@ struct c_common_resword
/* A token type for pre-parsed C++0x decltype. */
#define CPP_DECLTYPE ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1))
+/* A token type for pre-parsed primary-expression (lambda- or statement-). */
+#define CPP_PREPARSED_EXPR ((enum cpp_ttype) (CPP_DECLTYPE + 1))
+
/* The number of token types, including C++-specific ones. */
-#define N_CP_TTYPES ((int) (CPP_DECLTYPE + 1))
+#define N_CP_TTYPES ((int) (CPP_PREPARSED_EXPR + 1))
/* Disable mask. Keywords are disabled if (reswords[i].disable &
mask) is _true_. Thus for keywords which are present in all
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 00f5269..97b373c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2014-10-14 Jason Merrill <jason@redhat.com>
+
+ PR c++/63455
+ * parser.c (struct saved_token_sentinel): New.
+ (cp_parser_statement): Use it.
+ (cp_parser_start_tentative_firewall): New.
+ (cp_parser_end_tentative_firewall): New.
+ (cp_parser_lambda_expression): Use them.
+ (cp_parser_statement_expr): New.
+ (cp_parser_primary_expression): Use it.
+
2014-10-14 DJ Delorie <dj@redhat.com>
* typeck.c (cp_common_type): Check for all __intN types, not just
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b5a3724..c730995 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1,4 +1,4 @@
-/* C++ Parser.
+/* -*- C++ -*- Parser.
Copyright (C) 2000-2014 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
@@ -1155,6 +1155,34 @@ cp_lexer_rollback_tokens (cp_lexer* lexer)
lexer->next_token = lexer->saved_tokens.pop ();
}
+/* RAII wrapper around the above functions, with sanity checking. Creating
+ a variable saves tokens, which are committed when the variable is
+ destroyed unless they are explicitly rolled back by calling the rollback
+ member function. */
+
+struct saved_token_sentinel
+{
+ cp_lexer *lexer;
+ unsigned len;
+ bool commit;
+ saved_token_sentinel(cp_lexer *lexer): lexer(lexer), commit(true)
+ {
+ len = lexer->saved_tokens.length ();
+ cp_lexer_save_tokens (lexer);
+ }
+ void rollback ()
+ {
+ cp_lexer_rollback_tokens (lexer);
+ commit = false;
+ }
+ ~saved_token_sentinel()
+ {
+ if (commit)
+ cp_lexer_commit_tokens (lexer);
+ gcc_assert (lexer->saved_tokens.length () == len);
+ }
+};
+
/* Print a representation of the TOKEN on the STREAM. */
static void
@@ -4107,6 +4135,65 @@ complain_flags (bool decltype_p)
return complain;
}
+/* We're about to parse a collection of statements. If we're currently
+ parsing tentatively, set up a firewall so that any nested
+ cp_parser_commit_to_tentative_parse won't affect the current context. */
+
+static cp_token_position
+cp_parser_start_tentative_firewall (cp_parser *parser)
+{
+ if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
+ return 0;
+
+ cp_parser_parse_tentatively (parser);
+ cp_parser_commit_to_topmost_tentative_parse (parser);
+ return cp_lexer_token_position (parser->lexer, false);
+}
+
+/* We've finished parsing the collection of statements. Wrap up the
+ firewall and replace the relevant tokens with the parsed form. */
+
+static void
+cp_parser_end_tentative_firewall (cp_parser *parser, cp_token_position start,
+ tree expr)
+{
+ if (!start)
+ return;
+
+ /* Finish the firewall level. */
+ cp_parser_parse_definitely (parser);
+ /* And remember the result of the parse for when we try again. */
+ cp_token *token = cp_lexer_token_at (parser->lexer, start);
+ token->type = CPP_PREPARSED_EXPR;
+ token->u.value = expr;
+ token->keyword = RID_MAX;
+ cp_lexer_purge_tokens_after (parser->lexer, start);
+}
+
+/* Parse a GNU statement-expression, i.e. ({ stmts }), except for the
+ enclosing parentheses. */
+
+static tree
+cp_parser_statement_expr (cp_parser *parser)
+{
+ cp_token_position start = cp_parser_start_tentative_firewall (parser);
+
+ /* Consume the '('. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Start the statement-expression. */
+ tree expr = begin_stmt_expr ();
+ /* Parse the compound-statement. */
+ cp_parser_compound_statement (parser, expr, false, false);
+ /* Finish up. */
+ expr = finish_stmt_expr (expr, false);
+ /* Consume the ')'. */
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+ cp_parser_skip_to_end_of_statement (parser);
+
+ cp_parser_end_tentative_firewall (parser, start, expr);
+ return expr;
+}
+
/* Expressions [gram.expr] */
/* Parse a primary-expression.
@@ -4193,6 +4280,7 @@ cp_parser_primary_expression (cp_parser *parser,
case CPP_CHAR32:
case CPP_WCHAR:
case CPP_NUMBER:
+ case CPP_PREPARSED_EXPR:
if (TREE_CODE (token->u.value) == USERDEF_LITERAL)
return cp_parser_userdef_numeric_literal (parser);
token = cp_lexer_consume_token (parser->lexer);
@@ -4272,6 +4360,36 @@ cp_parser_primary_expression (cp_parser *parser,
true);
case CPP_OPEN_PAREN:
+ /* If we see `( { ' then we are looking at the beginning of
+ a GNU statement-expression. */
+ if (cp_parser_allow_gnu_extensions_p (parser)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE))
+ {
+ /* Statement-expressions are not allowed by the standard. */
+ pedwarn (token->location, OPT_Wpedantic,
+ "ISO C++ forbids braced-groups within expressions");
+
+ /* And they're not allowed outside of a function-body; you
+ cannot, for example, write:
+
+ int i = ({ int j = 3; j + 1; });
+
+ at class or namespace scope. */
+ if (!parser->in_function_body
+ || parser->in_template_argument_list_p)
+ {
+ error_at (token->location,
+ "statement-expressions are not allowed outside "
+ "functions nor in template-argument lists");
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+ cp_lexer_consume_token (parser->lexer);
+ return error_mark_node;
+ }
+ else
+ return cp_parser_statement_expr (parser);
+ }
+ /* Otherwise it's a normal parenthesized expression. */
{
tree expr;
bool saved_greater_than_is_operator_p;
@@ -4283,57 +4401,22 @@ cp_parser_primary_expression (cp_parser *parser,
saved_greater_than_is_operator_p
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = true;
- /* If we see `( { ' then we are looking at the beginning of
- a GNU statement-expression. */
- if (cp_parser_allow_gnu_extensions_p (parser)
- && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
- {
- /* Statement-expressions are not allowed by the standard. */
- pedwarn (token->location, OPT_Wpedantic,
- "ISO C++ forbids braced-groups within expressions");
-
- /* And they're not allowed outside of a function-body; you
- cannot, for example, write:
- int i = ({ int j = 3; j + 1; });
+ /* Parse the parenthesized expression. */
+ expr = cp_parser_expression (parser, idk, cast_p, decltype_p);
+ /* Let the front end know that this expression was
+ enclosed in parentheses. This matters in case, for
+ example, the expression is of the form `A::B', since
+ `&A::B' might be a pointer-to-member, but `&(A::B)' is
+ not. */
+ expr = finish_parenthesized_expr (expr);
+ /* DR 705: Wrapping an unqualified name in parentheses
+ suppresses arg-dependent lookup. We want to pass back
+ CP_ID_KIND_QUALIFIED for suppressing vtable lookup
+ (c++/37862), but none of the others. */
+ if (*idk != CP_ID_KIND_QUALIFIED)
+ *idk = CP_ID_KIND_NONE;
- at class or namespace scope. */
- if (!parser->in_function_body
- || parser->in_template_argument_list_p)
- {
- error_at (token->location,
- "statement-expressions are not allowed outside "
- "functions nor in template-argument lists");
- cp_parser_skip_to_end_of_block_or_statement (parser);
- expr = error_mark_node;
- }
- else
- {
- /* Start the statement-expression. */
- expr = begin_stmt_expr ();
- /* Parse the compound-statement. */
- cp_parser_compound_statement (parser, expr, false, false);
- /* Finish up. */
- expr = finish_stmt_expr (expr, false);
- }
- }
- else
- {
- /* Parse the parenthesized expression. */
- expr = cp_parser_expression (parser, idk, cast_p, decltype_p);
- /* Let the front end know that this expression was
- enclosed in parentheses. This matters in case, for
- example, the expression is of the form `A::B', since
- `&A::B' might be a pointer-to-member, but `&(A::B)' is
- not. */
- expr = finish_parenthesized_expr (expr);
- /* DR 705: Wrapping an unqualified name in parentheses
- suppresses arg-dependent lookup. We want to pass back
- CP_ID_KIND_QUALIFIED for suppressing vtable lookup
- (c++/37862), but none of the others. */
- if (*idk != CP_ID_KIND_QUALIFIED)
- *idk = CP_ID_KIND_NONE;
- }
/* The `>' token might be the end of a template-id or
template-parameter-list now. */
parser->greater_than_is_operator_p
@@ -8869,6 +8952,7 @@ cp_parser_lambda_expression (cp_parser* parser)
tree type;
bool ok = true;
cp_token *token = cp_lexer_peek_token (parser->lexer);
+ cp_token_position start = 0;
LAMBDA_EXPR_LOCATION (lambda_expr) = token->location;
@@ -8882,6 +8966,15 @@ cp_parser_lambda_expression (cp_parser* parser)
}
ok = false;
}
+ else if (parser->in_template_argument_list_p)
+ {
+ if (!token->error_reported)
+ {
+ error_at (token->location, "lambda-expression in template-argument");
+ token->error_reported = true;
+ }
+ ok = false;
+ }
/* We may be in the middle of deferred access check. Disable
it now. */
@@ -8929,7 +9022,13 @@ cp_parser_lambda_expression (cp_parser* parser)
ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
if (ok)
- cp_parser_lambda_body (parser, lambda_expr);
+ {
+ if (!cp_parser_error_occurred (parser)
+ && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)
+ && cp_parser_start_tentative_firewall (parser))
+ start = token;
+ cp_parser_lambda_body (parser, lambda_expr);
+ }
else if (cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
{
if (cp_parser_skip_to_closing_brace (parser))
@@ -8967,9 +9066,13 @@ cp_parser_lambda_expression (cp_parser* parser)
insert_pending_capture_proxies ();
if (ok)
- return build_lambda_object (lambda_expr);
+ lambda_expr = build_lambda_object (lambda_expr);
else
- return error_mark_node;
+ lambda_expr = error_mark_node;
+
+ cp_parser_end_tentative_firewall (parser, start, lambda_expr);
+
+ return lambda_expr;
}
/* Parse the beginning of a lambda expression.
@@ -9503,7 +9606,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
/* There is no statement yet. */
statement = NULL_TREE;
- cp_lexer_save_tokens (parser->lexer);
+ saved_token_sentinel saved_tokens (parser->lexer);
attrs_location = cp_lexer_peek_token (parser->lexer)->location;
if (c_dialect_objc ())
/* In obj-c++, seeing '[[' might be the either the beginning of
@@ -9668,7 +9771,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
{
/* Attributes should be parsed as part of the the
declaration, so let's un-parse them. */
- cp_lexer_rollback_tokens (parser->lexer);
+ saved_tokens.rollback();
std_attrs = NULL_TREE;
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-sfinae1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-sfinae1.C
index 973f8a7..40abcb9 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-sfinae1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-sfinae1.C
@@ -8,9 +8,9 @@ struct AddRvalueReferenceImpl { typedef T type; };
template <typename T>
struct AddRvalueReferenceImpl<T, typename BoolSink<false &&
- [] {
+ [] { // { dg-error "lambda" }
extern T &&tref;
- }>::type> { // { dg-error "lambda" }
+ }>::type> {
typedef T &&type;
};
@@ -27,9 +27,9 @@ struct IsConstructibleImpl { enum { value = 0 }; };
template <typename T, typename ...Args>
struct IsConstructibleImpl<T, typename BoolSink<false &&
- [] {
+ [] { // { dg-error "lambda" }
T t( ::ImplHelpers::create<Args>() ...);
- }>::type, Args ...> { // { dg-error "lambda" }
+ }>::type, Args ...> {
enum { value = 1 };
};
@@ -53,3 +53,4 @@ static_assert(+IsConstructible<int &&, int &&>::value, "error");
// { dg-prune-output "expected" }
// { dg-prune-output "does not name a class" }
// { dg-prune-output "static assertion" }
+// { dg-prune-output "template argument . is invalid" }
diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr16.C b/gcc/testsuite/g++.dg/ext/stmtexpr16.C
new file mode 100644
index 0000000..ddce40c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/stmtexpr16.C
@@ -0,0 +1,10 @@
+// PR c++/63455
+// { dg-options "-std=gnu++11" }
+
+int main()
+{
+ int x = 0;
+
+ // without '+0', gcc 4.6 gives a different error (no ICE though)
+ decltype(({ int y = x; y; })+0) v1 = 0;
+}