mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
327a79a523
commit
5f83e90bb6
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
159
gcc/cp/parser.c
159
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,21 +4360,10 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
true);
|
||||
|
||||
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
|
||||
a GNU statement-expression. */
|
||||
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. */
|
||||
pedwarn (token->location, OPT_Wpedantic,
|
||||
|
|
@ -4305,20 +4382,26 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
"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;
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
return 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);
|
||||
return cp_parser_statement_expr (parser);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Otherwise it's a normal parenthesized expression. */
|
||||
{
|
||||
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. */
|
||||
expr = cp_parser_expression (parser, idk, cast_p, decltype_p);
|
||||
/* Let the front end know that this expression was
|
||||
|
|
@ -4333,7 +4416,7 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
(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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue