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>
|
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
|
||||||
/* 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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
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
|
||||||
|
|
|
||||||
213
gcc/cp/parser.c
213
gcc/cp/parser.c
|
|
@ -1,4 +1,4 @@
|
||||||
/* 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)
|
||||||
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)
|
||||||
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,
|
||||||
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,6 +4360,36 @@ cp_parser_primary_expression (cp_parser *parser,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
case CPP_OPEN_PAREN:
|
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;
|
tree expr;
|
||||||
bool saved_greater_than_is_operator_p;
|
bool saved_greater_than_is_operator_p;
|
||||||
|
|
@ -4283,57 +4401,22 @@ cp_parser_primary_expression (cp_parser *parser,
|
||||||
saved_greater_than_is_operator_p
|
saved_greater_than_is_operator_p
|
||||||
= parser->greater_than_is_operator_p;
|
= parser->greater_than_is_operator_p;
|
||||||
parser->greater_than_is_operator_p = true;
|
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
|
/* Parse the parenthesized expression. */
|
||||||
cannot, for example, write:
|
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;
|
||||||
|
|
||||||
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);
|
|
||||||
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
|
/* 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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
|
ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
|
||||||
|
|
||||||
if (ok)
|
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))
|
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)
|
||||||
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,
|
||||||
/* 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,
|
||||||
{
|
{
|
||||||
/* 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; };
|
||||||
|
|
||||||
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 }; };
|
||||||
|
|
||||||
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");
|
||||||
// { 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" }
|
||||||
|
|
|
||||||
|
|
@ -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