re PR c++/67810 (Non-expression recognized as fold expression)
PR c++/67810 * parser.c (cp_parser_fold_expr_p): Remove. (is_binary_op): New. (cp_parser_fold_expression): Take LHS as parameter. (cp_parser_primary_expression): Call it after parsing an expression. (cp_parser_binary_expression, cp_parser_assignment_operator_opt) (cp_parser_expression): Ignore an operator followed by '...'. (is_binary_op): New. * pt.c (tsubst_unary_left_fold, tsubst_binary_left_fold) (tsubst_unary_right_fold, tsubst_binary_right_fold): Handle errors. From-SVN: r228556
This commit is contained in:
parent
437d8c8089
commit
8237beb118
|
@ -1,3 +1,16 @@
|
|||
2015-10-06 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/67810
|
||||
* parser.c (cp_parser_fold_expr_p): Remove.
|
||||
(is_binary_op): New.
|
||||
(cp_parser_fold_expression): Take LHS as parameter.
|
||||
(cp_parser_primary_expression): Call it after parsing an expression.
|
||||
(cp_parser_binary_expression, cp_parser_assignment_operator_opt)
|
||||
(cp_parser_expression): Ignore an operator followed by '...'.
|
||||
(is_binary_op): New.
|
||||
* pt.c (tsubst_unary_left_fold, tsubst_binary_left_fold)
|
||||
(tsubst_unary_right_fold, tsubst_binary_right_fold): Handle errors.
|
||||
|
||||
2015-10-06 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/67863
|
||||
|
|
157
gcc/cp/parser.c
157
gcc/cp/parser.c
|
@ -4339,6 +4339,50 @@ cp_parser_fold_operator (cp_token *token)
|
|||
}
|
||||
}
|
||||
|
||||
/* Returns true if CODE indicates a binary expression, which is not allowed in
|
||||
the LHS of a fold-expression. More codes will need to be added to use this
|
||||
function in other contexts. */
|
||||
|
||||
static bool
|
||||
is_binary_op (tree_code code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case PLUS_EXPR:
|
||||
case POINTER_PLUS_EXPR:
|
||||
case MINUS_EXPR:
|
||||
case MULT_EXPR:
|
||||
case TRUNC_DIV_EXPR:
|
||||
case TRUNC_MOD_EXPR:
|
||||
case BIT_XOR_EXPR:
|
||||
case BIT_AND_EXPR:
|
||||
case BIT_IOR_EXPR:
|
||||
case LSHIFT_EXPR:
|
||||
case RSHIFT_EXPR:
|
||||
|
||||
case MODOP_EXPR:
|
||||
|
||||
case EQ_EXPR:
|
||||
case NE_EXPR:
|
||||
case LE_EXPR:
|
||||
case GE_EXPR:
|
||||
case LT_EXPR:
|
||||
case GT_EXPR:
|
||||
|
||||
case TRUTH_ANDIF_EXPR:
|
||||
case TRUTH_ORIF_EXPR:
|
||||
|
||||
case COMPOUND_EXPR:
|
||||
|
||||
case DOTSTAR_EXPR:
|
||||
case MEMBER_REF:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the next token is a suitable fold operator, consume it and return as
|
||||
the function above. */
|
||||
|
||||
|
@ -4352,41 +4396,6 @@ cp_parser_fold_operator (cp_parser *parser)
|
|||
return code;
|
||||
}
|
||||
|
||||
/* Returns true iff we're at the beginning of an N4191 fold-expression, after
|
||||
the left parenthesis. Rather than do tentative parsing, we scan the tokens
|
||||
up to the matching right paren for an ellipsis next to a binary
|
||||
operator. */
|
||||
|
||||
static bool
|
||||
cp_parser_fold_expr_p (cp_parser *parser)
|
||||
{
|
||||
/* An ellipsis right after the left paren always indicates a
|
||||
fold-expression. */
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
|
||||
{
|
||||
/* But if there isn't a fold operator after the ellipsis,
|
||||
give a different error. */
|
||||
cp_token *token = cp_lexer_peek_nth_token (parser->lexer, 2);
|
||||
return (cp_parser_fold_operator (token) != ERROR_MARK);
|
||||
}
|
||||
|
||||
/* Otherwise, look for an ellipsis. */
|
||||
cp_lexer_save_tokens (parser->lexer);
|
||||
int ret = cp_parser_skip_to_closing_parenthesis_1 (parser, false,
|
||||
CPP_ELLIPSIS, false);
|
||||
bool found = (ret == -1);
|
||||
if (found)
|
||||
{
|
||||
/* We found an ellipsis, is the previous token an operator? */
|
||||
cp_token *token = cp_lexer_peek_token (parser->lexer);
|
||||
--token;
|
||||
if (cp_parser_fold_operator (token) == ERROR_MARK)
|
||||
found = false;
|
||||
}
|
||||
cp_lexer_rollback_tokens (parser->lexer);
|
||||
return found;
|
||||
}
|
||||
|
||||
/* Parse a fold-expression.
|
||||
|
||||
fold-expression:
|
||||
|
@ -4397,14 +4406,10 @@ cp_parser_fold_expr_p (cp_parser *parser)
|
|||
Note that the '(' and ')' are matched in primary expression. */
|
||||
|
||||
static tree
|
||||
cp_parser_fold_expression (cp_parser *parser)
|
||||
cp_parser_fold_expression (cp_parser *parser, tree expr1)
|
||||
{
|
||||
cp_id_kind pidk;
|
||||
|
||||
if (cxx_dialect < cxx1z && !in_system_header_at (input_location))
|
||||
pedwarn (input_location, 0, "fold-expressions only available with "
|
||||
"-std=c++1z or -std=gnu++1z");
|
||||
|
||||
// Left fold.
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
|
||||
{
|
||||
|
@ -4423,10 +4428,6 @@ cp_parser_fold_expression (cp_parser *parser)
|
|||
return finish_left_unary_fold_expr (expr, op);
|
||||
}
|
||||
|
||||
tree expr1 = cp_parser_cast_expression (parser, false, false, false, &pidk);
|
||||
if (expr1 == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
const cp_token* token = cp_lexer_peek_token (parser->lexer);
|
||||
int op = cp_parser_fold_operator (parser);
|
||||
if (op == ERROR_MARK)
|
||||
|
@ -4442,6 +4443,16 @@ cp_parser_fold_expression (cp_parser *parser)
|
|||
}
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
||||
/* The operands of a fold-expression are cast-expressions, so binary or
|
||||
conditional expressions are not allowed. We check this here to avoid
|
||||
tentative parsing. */
|
||||
if (is_binary_op (TREE_CODE (expr1)))
|
||||
error_at (location_of (expr1),
|
||||
"binary expression in operand of fold-expression");
|
||||
else if (TREE_CODE (expr1) == COND_EXPR)
|
||||
error_at (location_of (expr1),
|
||||
"conditional expression in operand of fold-expression");
|
||||
|
||||
// Right fold.
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
|
||||
return finish_right_unary_fold_expr (expr1, op);
|
||||
|
@ -4668,22 +4679,31 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
= parser->greater_than_is_operator_p;
|
||||
parser->greater_than_is_operator_p = true;
|
||||
|
||||
// Handle a fold-expression.
|
||||
if (cp_parser_fold_expr_p (parser))
|
||||
{
|
||||
tree fold = cp_parser_fold_expression (parser);
|
||||
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
|
||||
return fold;
|
||||
}
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
|
||||
/* Left fold expression. */
|
||||
expr = NULL_TREE;
|
||||
else
|
||||
/* Parse the parenthesized expression. */
|
||||
expr = cp_parser_expression (parser, idk, cast_p, decltype_p);
|
||||
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
if (token->type == CPP_ELLIPSIS || cp_parser_fold_operator (token))
|
||||
{
|
||||
expr = cp_parser_fold_expression (parser, expr);
|
||||
if (expr != error_mark_node
|
||||
&& cxx_dialect < cxx1z
|
||||
&& !in_system_header_at (input_location))
|
||||
pedwarn (input_location, 0, "fold-expressions only available "
|
||||
"with -std=c++1z or -std=gnu++1z");
|
||||
}
|
||||
else
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
|
@ -8468,6 +8488,10 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
|
|||
}
|
||||
|
||||
new_prec = TOKEN_PRECEDENCE (token);
|
||||
if (new_prec != PREC_NOT_OPERATOR
|
||||
&& cp_lexer_nth_token_is (parser->lexer, 2, CPP_ELLIPSIS))
|
||||
/* This is a fold-expression; handle it later. */
|
||||
new_prec = PREC_NOT_OPERATOR;
|
||||
|
||||
/* Popping an entry off the stack means we completed a subexpression:
|
||||
- either we found a token which is not an operator (`>' where it is not
|
||||
|
@ -8509,6 +8533,9 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
|
|||
cases such as 3 + 4 + 5 or 3 * 4 + 5. */
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
lookahead_prec = TOKEN_PRECEDENCE (token);
|
||||
if (lookahead_prec != PREC_NOT_OPERATOR
|
||||
&& cp_lexer_nth_token_is (parser->lexer, 2, CPP_ELLIPSIS))
|
||||
lookahead_prec = PREC_NOT_OPERATOR;
|
||||
if (lookahead_prec > new_prec)
|
||||
{
|
||||
/* ... and prepare to parse the RHS of the new, higher priority
|
||||
|
@ -8824,6 +8851,11 @@ cp_parser_assignment_operator_opt (cp_parser* parser)
|
|||
op = ERROR_MARK;
|
||||
}
|
||||
|
||||
/* An operator followed by ... is a fold-expression, handled elsewhere. */
|
||||
if (op != ERROR_MARK
|
||||
&& cp_lexer_nth_token_is (parser->lexer, 2, CPP_ELLIPSIS))
|
||||
op = ERROR_MARK;
|
||||
|
||||
/* If it was an assignment operator, consume it. */
|
||||
if (op != ERROR_MARK)
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
@ -8877,9 +8909,10 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
|
|||
expression = build_x_compound_expr (loc, expression,
|
||||
assignment_expression,
|
||||
complain_flags (decltype_p));
|
||||
/* If the next token is not a comma, then we are done with the
|
||||
expression. */
|
||||
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
|
||||
/* If the next token is not a comma, or we're in a fold-expression, then
|
||||
we are done with the expression. */
|
||||
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
|
||||
|| cp_lexer_nth_token_is (parser->lexer, 2, CPP_ELLIPSIS))
|
||||
break;
|
||||
/* Consume the `,'. */
|
||||
loc = cp_lexer_peek_token (parser->lexer)->location;
|
||||
|
|
12
gcc/cp/pt.c
12
gcc/cp/pt.c
|
@ -10632,6 +10632,8 @@ tsubst_unary_left_fold (tree t, tree args, tsubst_flags_t complain,
|
|||
tree in_decl)
|
||||
{
|
||||
tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
|
||||
if (pack == error_mark_node)
|
||||
return error_mark_node;
|
||||
if (TREE_VEC_LENGTH (pack) == 0)
|
||||
return expand_empty_fold (t, complain);
|
||||
else
|
||||
|
@ -10648,7 +10650,11 @@ tsubst_binary_left_fold (tree t, tree args, tsubst_flags_t complain,
|
|||
tree in_decl)
|
||||
{
|
||||
tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
|
||||
if (pack == error_mark_node)
|
||||
return error_mark_node;
|
||||
tree init = tsubst_fold_expr_init (t, args, complain, in_decl);
|
||||
if (init == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
tree vec = make_tree_vec (TREE_VEC_LENGTH (pack) + 1);
|
||||
TREE_VEC_ELT (vec, 0) = init;
|
||||
|
@ -10689,6 +10695,8 @@ tsubst_unary_right_fold (tree t, tree args, tsubst_flags_t complain,
|
|||
tree in_decl)
|
||||
{
|
||||
tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
|
||||
if (pack == error_mark_node)
|
||||
return error_mark_node;
|
||||
if (TREE_VEC_LENGTH (pack) == 0)
|
||||
return expand_empty_fold (t, complain);
|
||||
else
|
||||
|
@ -10705,7 +10713,11 @@ tsubst_binary_right_fold (tree t, tree args, tsubst_flags_t complain,
|
|||
tree in_decl)
|
||||
{
|
||||
tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
|
||||
if (pack == error_mark_node)
|
||||
return error_mark_node;
|
||||
tree init = tsubst_fold_expr_init (t, args, complain, in_decl);
|
||||
if (init == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
int n = TREE_VEC_LENGTH (pack);
|
||||
tree vec = make_tree_vec (n + 1);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// PR c++/67810
|
||||
// { dg-do compile { target c++14 } }
|
||||
|
||||
template <class...>
|
||||
constexpr bool Test = true;
|
||||
|
||||
template <typename...Ts, bool = (Test<Ts&&...>)>
|
||||
void f();
|
|
@ -54,8 +54,8 @@ MAKE_FNS (eq, ==);
|
|||
MAKE_FNS (ne, !=);
|
||||
MAKE_FNS (lt, <);
|
||||
MAKE_FNS (gt, >);
|
||||
MAKE_FNS (le, <);
|
||||
MAKE_FNS (ge, >);
|
||||
MAKE_FNS (le, <=);
|
||||
MAKE_FNS (ge, >=);
|
||||
|
||||
MAKE_FNS (land, &&);
|
||||
MAKE_FNS (lor, ||);
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// Test that we reject a fold-expression with an LHS that is not a
|
||||
// cast-expression.
|
||||
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
int i;
|
||||
|
||||
template <int... Is>
|
||||
int f()
|
||||
{
|
||||
(i ? i : Is + ...); // { dg-error "" }
|
||||
(i + Is + ...); // { dg-error "" }
|
||||
(i - Is + ...); // { dg-error "" }
|
||||
(i * Is + ...); // { dg-error "" }
|
||||
(i / Is + ...); // { dg-error "" }
|
||||
(i % Is + ...); // { dg-error "" }
|
||||
(i ^ Is + ...); // { dg-error "" }
|
||||
(i | Is + ...); // { dg-error "" }
|
||||
(i & Is + ...); // { dg-error "" }
|
||||
(i << Is + ...); // { dg-error "" }
|
||||
(i >> Is + ...); // { dg-error "" }
|
||||
(i = Is + ...); // { dg-error "" }
|
||||
(i += Is + ...); // { dg-error "" }
|
||||
(i -= Is + ...); // { dg-error "" }
|
||||
(i *= Is + ...); // { dg-error "" }
|
||||
(i /= Is + ...); // { dg-error "" }
|
||||
(i %= Is + ...); // { dg-error "" }
|
||||
(i ^= Is + ...); // { dg-error "" }
|
||||
(i |= Is + ...); // { dg-error "" }
|
||||
(i &= Is + ...); // { dg-error "" }
|
||||
(i <<= Is + ...); // { dg-error "" }
|
||||
(i >>= Is + ...); // { dg-error "" }
|
||||
(i == Is + ...); // { dg-error "" }
|
||||
(i != Is + ...); // { dg-error "" }
|
||||
(i < Is + ...); // { dg-error "" }
|
||||
(i > Is + ...); // { dg-error "" }
|
||||
(i <= Is + ...); // { dg-error "" }
|
||||
(i >= Is + ...); // { dg-error "" }
|
||||
(i && Is + ...); // { dg-error "" }
|
||||
(i || Is + ...); // { dg-error "" }
|
||||
(i , Is + ...); // { dg-error "" }
|
||||
}
|
Loading…
Reference in New Issue