Commit 5f83e90b by Jason Merrill Committed by Jason Merrill

re PR c++/63455 (decltype of statement expression internal compiler error: in…

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
parent 327a79a5
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> 2014-10-15 Marek Polacek <polacek@redhat.com>
* c-opts.c (c_common_init_options): Make -std=gnu11 the default for C. * c-opts.c (c_common_init_options): Make -std=gnu11 the default for C.
......
...@@ -361,8 +361,11 @@ struct c_common_resword ...@@ -361,8 +361,11 @@ struct c_common_resword
/* A token type for pre-parsed C++0x decltype. */ /* A token type for pre-parsed C++0x decltype. */
#define CPP_DECLTYPE ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1)) #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. */ /* 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 & /* Disable mask. Keywords are disabled if (reswords[i].disable &
mask) is _true_. Thus for keywords which are present in all mask) is _true_. Thus for keywords which are present in all
......
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> 2014-10-14 DJ Delorie <dj@redhat.com>
* typeck.c (cp_common_type): Check for all __intN types, not just * typeck.c (cp_common_type): Check for all __intN types, not just
......
/* C++ Parser. /* -*- C++ -*- Parser.
Copyright (C) 2000-2014 Free Software Foundation, Inc. Copyright (C) 2000-2014 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>. Written by Mark Mitchell <mark@codesourcery.com>.
...@@ -1155,6 +1155,34 @@ cp_lexer_rollback_tokens (cp_lexer* lexer) ...@@ -1155,6 +1155,34 @@ cp_lexer_rollback_tokens (cp_lexer* lexer)
lexer->next_token = lexer->saved_tokens.pop (); 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. */ /* Print a representation of the TOKEN on the STREAM. */
static void static void
...@@ -4107,6 +4135,65 @@ complain_flags (bool decltype_p) ...@@ -4107,6 +4135,65 @@ complain_flags (bool decltype_p)
return complain; 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] */ /* Expressions [gram.expr] */
/* Parse a primary-expression. /* Parse a primary-expression.
...@@ -4193,6 +4280,7 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -4193,6 +4280,7 @@ cp_parser_primary_expression (cp_parser *parser,
case CPP_CHAR32: case CPP_CHAR32:
case CPP_WCHAR: case CPP_WCHAR:
case CPP_NUMBER: case CPP_NUMBER:
case CPP_PREPARSED_EXPR:
if (TREE_CODE (token->u.value) == USERDEF_LITERAL) if (TREE_CODE (token->u.value) == USERDEF_LITERAL)
return cp_parser_userdef_numeric_literal (parser); return cp_parser_userdef_numeric_literal (parser);
token = cp_lexer_consume_token (parser->lexer); token = cp_lexer_consume_token (parser->lexer);
...@@ -4272,21 +4360,10 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -4272,21 +4360,10 @@ cp_parser_primary_expression (cp_parser *parser,
true); true);
case CPP_OPEN_PAREN: case CPP_OPEN_PAREN:
{
tree expr;
bool saved_greater_than_is_operator_p;
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* Within a parenthesized expression, a `>' token is always
the greater-than operator. */
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 /* If we see `( { ' then we are looking at the beginning of
a GNU statement-expression. */ a GNU statement-expression. */
if (cp_parser_allow_gnu_extensions_p (parser) if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE))
{ {
/* Statement-expressions are not allowed by the standard. */ /* Statement-expressions are not allowed by the standard. */
pedwarn (token->location, OPT_Wpedantic, pedwarn (token->location, OPT_Wpedantic,
...@@ -4305,20 +4382,26 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -4305,20 +4382,26 @@ cp_parser_primary_expression (cp_parser *parser,
"statement-expressions are not allowed outside " "statement-expressions are not allowed outside "
"functions nor in template-argument lists"); "functions nor in template-argument lists");
cp_parser_skip_to_end_of_block_or_statement (parser); cp_parser_skip_to_end_of_block_or_statement (parser);
expr = error_mark_node; if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
cp_lexer_consume_token (parser->lexer);
return error_mark_node;
} }
else else
{ return cp_parser_statement_expr (parser);
/* 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);
} }
} /* Otherwise it's a normal parenthesized expression. */
else
{ {
tree expr;
bool saved_greater_than_is_operator_p;
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* Within a parenthesized expression, a `>' token is always
the greater-than operator. */
saved_greater_than_is_operator_p
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = true;
/* Parse the parenthesized expression. */ /* Parse the parenthesized expression. */
expr = cp_parser_expression (parser, idk, cast_p, decltype_p); expr = cp_parser_expression (parser, idk, cast_p, decltype_p);
/* Let the front end know that this expression was /* Let the front end know that this expression was
...@@ -4333,7 +4416,7 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -4333,7 +4416,7 @@ cp_parser_primary_expression (cp_parser *parser,
(c++/37862), but none of the others. */ (c++/37862), but none of the others. */
if (*idk != CP_ID_KIND_QUALIFIED) if (*idk != CP_ID_KIND_QUALIFIED)
*idk = CP_ID_KIND_NONE; *idk = CP_ID_KIND_NONE;
}
/* The `>' token might be the end of a template-id or /* The `>' token might be the end of a template-id or
template-parameter-list now. */ template-parameter-list now. */
parser->greater_than_is_operator_p parser->greater_than_is_operator_p
...@@ -8869,6 +8952,7 @@ cp_parser_lambda_expression (cp_parser* parser) ...@@ -8869,6 +8952,7 @@ cp_parser_lambda_expression (cp_parser* parser)
tree type; tree type;
bool ok = true; bool ok = true;
cp_token *token = cp_lexer_peek_token (parser->lexer); cp_token *token = cp_lexer_peek_token (parser->lexer);
cp_token_position start = 0;
LAMBDA_EXPR_LOCATION (lambda_expr) = token->location; LAMBDA_EXPR_LOCATION (lambda_expr) = token->location;
...@@ -8882,6 +8966,15 @@ cp_parser_lambda_expression (cp_parser* parser) ...@@ -8882,6 +8966,15 @@ cp_parser_lambda_expression (cp_parser* parser)
} }
ok = false; 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 /* We may be in the middle of deferred access check. Disable
it now. */ it now. */
...@@ -8929,7 +9022,13 @@ cp_parser_lambda_expression (cp_parser* parser) ...@@ -8929,7 +9022,13 @@ cp_parser_lambda_expression (cp_parser* parser)
ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr); ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
if (ok) if (ok)
{
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); cp_parser_lambda_body (parser, lambda_expr);
}
else if (cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE)) else if (cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
{ {
if (cp_parser_skip_to_closing_brace (parser)) if (cp_parser_skip_to_closing_brace (parser))
...@@ -8967,9 +9066,13 @@ cp_parser_lambda_expression (cp_parser* parser) ...@@ -8967,9 +9066,13 @@ cp_parser_lambda_expression (cp_parser* parser)
insert_pending_capture_proxies (); insert_pending_capture_proxies ();
if (ok) if (ok)
return build_lambda_object (lambda_expr); lambda_expr = build_lambda_object (lambda_expr);
else 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. /* Parse the beginning of a lambda expression.
...@@ -9503,7 +9606,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, ...@@ -9503,7 +9606,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
/* There is no statement yet. */ /* There is no statement yet. */
statement = NULL_TREE; 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; attrs_location = cp_lexer_peek_token (parser->lexer)->location;
if (c_dialect_objc ()) if (c_dialect_objc ())
/* In obj-c++, seeing '[[' might be the either the beginning of /* 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, ...@@ -9668,7 +9771,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
{ {
/* Attributes should be parsed as part of the the /* Attributes should be parsed as part of the the
declaration, so let's un-parse them. */ declaration, so let's un-parse them. */
cp_lexer_rollback_tokens (parser->lexer); saved_tokens.rollback();
std_attrs = NULL_TREE; std_attrs = NULL_TREE;
} }
......
...@@ -8,9 +8,9 @@ struct AddRvalueReferenceImpl { typedef T type; }; ...@@ -8,9 +8,9 @@ struct AddRvalueReferenceImpl { typedef T type; };
template <typename T> template <typename T>
struct AddRvalueReferenceImpl<T, typename BoolSink<false && struct AddRvalueReferenceImpl<T, typename BoolSink<false &&
[] { [] { // { dg-error "lambda" }
extern T &&tref; extern T &&tref;
}>::type> { // { dg-error "lambda" } }>::type> {
typedef T &&type; typedef T &&type;
}; };
...@@ -27,9 +27,9 @@ struct IsConstructibleImpl { enum { value = 0 }; }; ...@@ -27,9 +27,9 @@ struct IsConstructibleImpl { enum { value = 0 }; };
template <typename T, typename ...Args> template <typename T, typename ...Args>
struct IsConstructibleImpl<T, typename BoolSink<false && struct IsConstructibleImpl<T, typename BoolSink<false &&
[] { [] { // { dg-error "lambda" }
T t( ::ImplHelpers::create<Args>() ...); T t( ::ImplHelpers::create<Args>() ...);
}>::type, Args ...> { // { dg-error "lambda" } }>::type, Args ...> {
enum { value = 1 }; enum { value = 1 };
}; };
...@@ -53,3 +53,4 @@ static_assert(+IsConstructible<int &&, int &&>::value, "error"); ...@@ -53,3 +53,4 @@ static_assert(+IsConstructible<int &&, int &&>::value, "error");
// { dg-prune-output "expected" } // { dg-prune-output "expected" }
// { dg-prune-output "does not name a class" } // { dg-prune-output "does not name a class" }
// { dg-prune-output "static assertion" } // { dg-prune-output "static assertion" }
// { dg-prune-output "template argument . is invalid" }
// 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment