Commit 56632b27 by Jason Merrill Committed by Jason Merrill

Handle C++14 constexpr flow control.

	* constexpr.c (cxx_eval_loop_expr, cxx_eval_switch_expr): New.
	(cxx_eval_statement_list): New.
	(cxx_eval_constant_expression): Handle LABEL_EXPR,
	CASE_LABEL_EXPR, GOTO_EXPR, LOOP_EXPR, SWITCH_EXPR.  Handle jump
	semantics of RETURN_EXPR.
	(many functions): Add jump_target parameter.
	(returns, breaks, continues, switches, label_matches): New.
	* cp-tree.h (LABEL_DECL_BREAK, LABEL_DECL_CONTINUE): New.
	* cp-gimplify.c (begin_bc_block): Set them.

From-SVN: r217670
parent 27d93d2c
2014-11-17 Jason Merrill <jason@redhat.com> 2014-11-17 Jason Merrill <jason@redhat.com>
Handle C++14 constexpr flow control.
* constexpr.c (cxx_eval_loop_expr, cxx_eval_switch_expr): New.
(cxx_eval_statement_list): New.
(cxx_eval_constant_expression): Handle LABEL_EXPR,
CASE_LABEL_EXPR, GOTO_EXPR, LOOP_EXPR, SWITCH_EXPR. Handle jump
semantics of RETURN_EXPR.
(many functions): Add jump_target parameter.
(returns, breaks, continues, switches, label_matches): New.
* cp-tree.h (LABEL_DECL_BREAK, LABEL_DECL_CONTINUE): New.
* cp-gimplify.c (begin_bc_block): Set them.
* cp-gimplify.c (genericize_cp_loop): Use LOOP_EXPR. * cp-gimplify.c (genericize_cp_loop): Use LOOP_EXPR.
(genericize_for_stmt): Handle null statement-list. (genericize_for_stmt): Handle null statement-list.
......
...@@ -871,7 +871,7 @@ struct constexpr_ctx { ...@@ -871,7 +871,7 @@ struct constexpr_ctx {
static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table; static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table;
static tree cxx_eval_constant_expression (const constexpr_ctx *, tree, static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
bool, bool, bool *, bool *); bool, bool, bool *, bool *, tree *);
/* Compute a hash value for a constexpr call representation. */ /* Compute a hash value for a constexpr call representation. */
...@@ -993,7 +993,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, ...@@ -993,7 +993,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t,
{ {
args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, i), args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, i),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
NULL);
if (allow_non_constant && *non_constant_p) if (allow_non_constant && *non_constant_p)
return t; return t;
} }
...@@ -1068,7 +1069,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, ...@@ -1068,7 +1069,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
} }
arg = cxx_eval_constant_expression (ctx, x, allow_non_constant, arg = cxx_eval_constant_expression (ctx, x, allow_non_constant,
TREE_CODE (type) == REFERENCE_TYPE, TREE_CODE (type) == REFERENCE_TYPE,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
/* Don't VERIFY_CONSTANT here. */ /* Don't VERIFY_CONSTANT here. */
if (*non_constant_p && allow_non_constant) if (*non_constant_p && allow_non_constant)
return; return;
...@@ -1149,7 +1150,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -1149,7 +1150,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
/* Might be a constexpr function pointer. */ /* Might be a constexpr function pointer. */
fun = cxx_eval_constant_expression (ctx, fun, allow_non_constant, fun = cxx_eval_constant_expression (ctx, fun, allow_non_constant,
/*addr*/false, non_constant_p, /*addr*/false, non_constant_p,
overflow_p); overflow_p, NULL);
STRIP_NOPS (fun); STRIP_NOPS (fun);
if (TREE_CODE (fun) == ADDR_EXPR) if (TREE_CODE (fun) == ADDR_EXPR)
fun = TREE_OPERAND (fun, 0); fun = TREE_OPERAND (fun, 0);
...@@ -1185,7 +1186,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -1185,7 +1186,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
{ {
tree arg = convert_from_reference (get_nth_callarg (t, 1)); tree arg = convert_from_reference (get_nth_callarg (t, 1));
return cxx_eval_constant_expression (ctx, arg, allow_non_constant, return cxx_eval_constant_expression (ctx, arg, allow_non_constant,
addr, non_constant_p, overflow_p); addr, non_constant_p,
overflow_p, NULL);
} }
else if (TREE_CODE (t) == AGGR_INIT_EXPR else if (TREE_CODE (t) == AGGR_INIT_EXPR
&& AGGR_INIT_ZERO_FIRST (t)) && AGGR_INIT_ZERO_FIRST (t))
...@@ -1281,7 +1283,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -1281,7 +1283,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
result = (cxx_eval_constant_expression result = (cxx_eval_constant_expression
(&new_ctx, new_call.fundef->body, (&new_ctx, new_call.fundef->body,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p)); non_constant_p, overflow_p, NULL));
} }
else else
{ {
...@@ -1321,8 +1323,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -1321,8 +1323,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
else else
ctx->values->put (res, NULL_TREE); ctx->values->put (res, NULL_TREE);
tree jump_target = NULL_TREE;
cxx_eval_constant_expression (ctx, body, allow_non_constant, cxx_eval_constant_expression (ctx, body, allow_non_constant,
addr, non_constant_p, overflow_p); addr, non_constant_p, overflow_p,
&jump_target);
if (VOID_TYPE_P (TREE_TYPE (res))) if (VOID_TYPE_P (TREE_TYPE (res)))
/* This can be null for a subobject constructor call, in /* This can be null for a subobject constructor call, in
...@@ -1454,7 +1458,8 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t, ...@@ -1454,7 +1458,8 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
tree r; tree r;
tree orig_arg = TREE_OPERAND (t, 0); tree orig_arg = TREE_OPERAND (t, 0);
tree arg = cxx_eval_constant_expression (ctx, orig_arg, allow_non_constant, tree arg = cxx_eval_constant_expression (ctx, orig_arg, allow_non_constant,
addr, non_constant_p, overflow_p); addr, non_constant_p, overflow_p,
NULL);
VERIFY_CONSTANT (arg); VERIFY_CONSTANT (arg);
if (arg == orig_arg) if (arg == orig_arg)
return t; return t;
...@@ -1477,11 +1482,11 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, ...@@ -1477,11 +1482,11 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
tree lhs, rhs; tree lhs, rhs;
lhs = cxx_eval_constant_expression (ctx, orig_lhs, lhs = cxx_eval_constant_expression (ctx, orig_lhs,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
VERIFY_CONSTANT (lhs); VERIFY_CONSTANT (lhs);
rhs = cxx_eval_constant_expression (ctx, orig_rhs, rhs = cxx_eval_constant_expression (ctx, orig_rhs,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
VERIFY_CONSTANT (rhs); VERIFY_CONSTANT (rhs);
if (lhs == orig_lhs && rhs == orig_rhs) if (lhs == orig_lhs && rhs == orig_rhs)
return t; return t;
...@@ -1497,20 +1502,24 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, ...@@ -1497,20 +1502,24 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
static tree static tree
cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr, bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{ {
tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
NULL);
VERIFY_CONSTANT (val); VERIFY_CONSTANT (val);
/* Don't VERIFY_CONSTANT the other operands. */ /* Don't VERIFY_CONSTANT the other operands. */
if (integer_zerop (val)) if (integer_zerop (val))
return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2), return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
jump_target);
return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
jump_target);
} }
/* Subroutine of cxx_eval_constant_expression. /* Subroutine of cxx_eval_constant_expression.
...@@ -1524,7 +1533,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, ...@@ -1524,7 +1533,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
tree oldary = TREE_OPERAND (t, 0); tree oldary = TREE_OPERAND (t, 0);
tree ary = cxx_eval_constant_expression (ctx, oldary, tree ary = cxx_eval_constant_expression (ctx, oldary,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
tree index, oldidx; tree index, oldidx;
HOST_WIDE_INT i; HOST_WIDE_INT i;
tree elem_type; tree elem_type;
...@@ -1534,7 +1543,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, ...@@ -1534,7 +1543,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
oldidx = TREE_OPERAND (t, 1); oldidx = TREE_OPERAND (t, 1);
index = cxx_eval_constant_expression (ctx, oldidx, index = cxx_eval_constant_expression (ctx, oldidx,
allow_non_constant, false, allow_non_constant, false,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
VERIFY_CONSTANT (index); VERIFY_CONSTANT (index);
if (addr && ary == oldary && index == oldidx) if (addr && ary == oldary && index == oldidx)
return t; return t;
...@@ -1565,7 +1574,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, ...@@ -1565,7 +1574,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
tree val = build_value_init (elem_type, tf_warning_or_error); tree val = build_value_init (elem_type, tf_warning_or_error);
return cxx_eval_constant_expression (ctx, val, return cxx_eval_constant_expression (ctx, val,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
NULL);
} }
if (!allow_non_constant) if (!allow_non_constant)
...@@ -1611,7 +1621,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, ...@@ -1611,7 +1621,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
tree orig_whole = TREE_OPERAND (t, 0); tree orig_whole = TREE_OPERAND (t, 0);
tree whole = cxx_eval_constant_expression (ctx, orig_whole, tree whole = cxx_eval_constant_expression (ctx, orig_whole,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
if (whole == orig_whole) if (whole == orig_whole)
return t; return t;
if (addr) if (addr)
...@@ -1670,7 +1680,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, ...@@ -1670,7 +1680,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
value = build_value_init (TREE_TYPE (t), tf_warning_or_error); value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
return cxx_eval_constant_expression (ctx, value, return cxx_eval_constant_expression (ctx, value,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
} }
/* Subroutine of cxx_eval_constant_expression. /* Subroutine of cxx_eval_constant_expression.
...@@ -1688,7 +1698,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, ...@@ -1688,7 +1698,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
HOST_WIDE_INT istart, isize; HOST_WIDE_INT istart, isize;
tree whole = cxx_eval_constant_expression (ctx, orig_whole, tree whole = cxx_eval_constant_expression (ctx, orig_whole,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
tree start, field, value; tree start, field, value;
unsigned HOST_WIDE_INT i; unsigned HOST_WIDE_INT i;
...@@ -1771,13 +1781,14 @@ cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t, ...@@ -1771,13 +1781,14 @@ cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t,
tree r; tree r;
tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
VERIFY_CONSTANT (lhs); VERIFY_CONSTANT (lhs);
if (tree_int_cst_equal (lhs, bailout_value)) if (tree_int_cst_equal (lhs, bailout_value))
return lhs; return lhs;
gcc_assert (tree_int_cst_equal (lhs, continue_value)); gcc_assert (tree_int_cst_equal (lhs, continue_value));
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, addr, non_constant_p, overflow_p); allow_non_constant, addr, non_constant_p,
overflow_p, NULL);
VERIFY_CONSTANT (r); VERIFY_CONSTANT (r);
return r; return r;
} }
...@@ -1920,7 +1931,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, ...@@ -1920,7 +1931,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
CONSTRUCTOR_APPEND_ELT (*p, index, new_ctx.ctor); CONSTRUCTOR_APPEND_ELT (*p, index, new_ctx.ctor);
tree elt = cxx_eval_constant_expression (&new_ctx, value, tree elt = cxx_eval_constant_expression (&new_ctx, value,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
NULL);
/* Don't VERIFY_CONSTANT here. */ /* Don't VERIFY_CONSTANT here. */
if (allow_non_constant && *non_constant_p) if (allow_non_constant && *non_constant_p)
break; break;
...@@ -2038,7 +2050,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, ...@@ -2038,7 +2050,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
we just pre-built above. */ we just pre-built above. */
eltinit = (cxx_eval_constant_expression eltinit = (cxx_eval_constant_expression
(&new_ctx, init, allow_non_constant, (&new_ctx, init, allow_non_constant,
addr, non_constant_p, overflow_p)); addr, non_constant_p, overflow_p, NULL));
} }
else else
{ {
...@@ -2052,7 +2064,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, ...@@ -2052,7 +2064,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
eltinit = force_rvalue (eltinit, tf_warning_or_error); eltinit = force_rvalue (eltinit, tf_warning_or_error);
eltinit = (cxx_eval_constant_expression eltinit = (cxx_eval_constant_expression
(&new_ctx, eltinit, allow_non_constant, addr, (&new_ctx, eltinit, allow_non_constant, addr,
non_constant_p, overflow_p)); non_constant_p, overflow_p, NULL));
} }
if (*non_constant_p && !allow_non_constant) if (*non_constant_p && !allow_non_constant)
break; break;
...@@ -2288,7 +2300,8 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, ...@@ -2288,7 +2300,8 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
{ {
tree orig_op0 = TREE_OPERAND (t, 0); tree orig_op0 = TREE_OPERAND (t, 0);
tree op0 = cxx_eval_constant_expression (ctx, orig_op0, allow_non_constant, tree op0 = cxx_eval_constant_expression (ctx, orig_op0, allow_non_constant,
/*addr*/false, non_constant_p, overflow_p); /*addr*/false, non_constant_p,
overflow_p, NULL);
bool empty_base = false; bool empty_base = false;
tree r; tree r;
...@@ -2301,7 +2314,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, ...@@ -2301,7 +2314,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
if (r) if (r)
r = cxx_eval_constant_expression (ctx, r, allow_non_constant, r = cxx_eval_constant_expression (ctx, r, allow_non_constant,
addr, non_constant_p, overflow_p); addr, non_constant_p, overflow_p, NULL);
else else
{ {
tree sub = op0; tree sub = op0;
...@@ -2403,7 +2416,8 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, ...@@ -2403,7 +2416,8 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
{ {
args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i), args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
NULL);
VERIFY_CONSTANT (args[i]); VERIFY_CONSTANT (args[i]);
} }
...@@ -2436,7 +2450,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, ...@@ -2436,7 +2450,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
tree target = TREE_OPERAND (t, 0); tree target = TREE_OPERAND (t, 0);
target = cxx_eval_constant_expression (ctx, target, target = cxx_eval_constant_expression (ctx, target,
allow_non_constant, true, allow_non_constant, true,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
if (*non_constant_p) if (*non_constant_p)
return t; return t;
...@@ -2512,7 +2526,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, ...@@ -2512,7 +2526,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
tree init = cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (t, 1), tree init = cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (t, 1),
allow_non_constant, false, allow_non_constant, false,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
if (target == object) if (target == object)
/* The hash table might have moved since the get earlier. */ /* The hash table might have moved since the get earlier. */
ctx->values->put (object, init); ctx->values->put (object, init);
...@@ -2542,12 +2556,12 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, ...@@ -2542,12 +2556,12 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
/* The operand as an lvalue. */ /* The operand as an lvalue. */
op = cxx_eval_constant_expression (ctx, op, allow_non_constant, true, op = cxx_eval_constant_expression (ctx, op, allow_non_constant, true,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
/* The operand as an rvalue. */ /* The operand as an rvalue. */
tree val = rvalue (op); tree val = rvalue (op);
val = cxx_eval_constant_expression (ctx, val, allow_non_constant, false, val = cxx_eval_constant_expression (ctx, val, allow_non_constant, false,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
VERIFY_CONSTANT (val); VERIFY_CONSTANT (val);
/* The modified value. */ /* The modified value. */
...@@ -2559,7 +2573,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, ...@@ -2559,7 +2573,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
/* Storing the modified value. */ /* Storing the modified value. */
tree store = build2 (MODIFY_EXPR, type, op, mod); tree store = build2 (MODIFY_EXPR, type, op, mod);
cxx_eval_constant_expression (ctx, store, allow_non_constant, cxx_eval_constant_expression (ctx, store, allow_non_constant,
true, non_constant_p, overflow_p); true, non_constant_p, overflow_p, NULL);
/* And the value of the expression. */ /* And the value of the expression. */
if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR) if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
...@@ -2576,6 +2590,159 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, ...@@ -2576,6 +2590,159 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
return val; return val;
} }
/* Predicates for the meaning of *jump_target. */
static bool
returns (tree *jump_target)
{
return *jump_target
&& TREE_CODE (*jump_target) == RETURN_EXPR;
}
static bool
breaks (tree *jump_target)
{
return *jump_target
&& TREE_CODE (*jump_target) == LABEL_DECL
&& LABEL_DECL_BREAK (*jump_target);
}
static bool
continues (tree *jump_target)
{
return *jump_target
&& TREE_CODE (*jump_target) == LABEL_DECL
&& LABEL_DECL_CONTINUE (*jump_target);
}
static bool
switches (tree *jump_target)
{
return *jump_target
&& TREE_CODE (*jump_target) == INTEGER_CST;
}
/* Subroutine of cxx_eval_statement_list. Determine whether the statement
at I matches *jump_target. If we're looking for a case label and we see
the default label, copy I into DEFAULT_LABEL. */
static bool
label_matches (tree *jump_target, tree_stmt_iterator i,
tree_stmt_iterator& default_label)
{
tree stmt = tsi_stmt (i);
switch (TREE_CODE (*jump_target))
{
case LABEL_DECL:
if (TREE_CODE (stmt) == LABEL_EXPR
&& LABEL_EXPR_LABEL (stmt) == *jump_target)
return true;
break;
case INTEGER_CST:
if (TREE_CODE (stmt) == CASE_LABEL_EXPR)
{
if (!CASE_LOW (stmt))
default_label = i;
else if (tree_int_cst_equal (*jump_target, CASE_LOW (stmt)))
return true;
}
break;
default:
gcc_unreachable ();
}
return false;
}
/* Evaluate a STATEMENT_LIST for side-effects. Handles various jump
semantics, for switch, break, continue, and return. */
static tree
cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
bool allow_non_constant,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
tree_stmt_iterator i;
tree_stmt_iterator default_label = tree_stmt_iterator();
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
{
reenter:
tree stmt = tsi_stmt (i);
if (*jump_target)
{
if (TREE_CODE (stmt) == STATEMENT_LIST)
/* The label we want might be inside. */;
else if (label_matches (jump_target, i, default_label))
/* Found it. */
*jump_target = NULL_TREE;
else
continue;
}
cxx_eval_constant_expression (ctx, stmt,
allow_non_constant, false,
non_constant_p, overflow_p,
jump_target);
if (*non_constant_p)
break;
if (returns (jump_target) || breaks (jump_target))
break;
}
if (switches (jump_target) && !tsi_end_p (default_label))
{
i = default_label;
*jump_target = NULL_TREE;
goto reenter;
}
return NULL_TREE;
}
/* Evaluate a LOOP_EXPR for side-effects. Handles break and return
semantics; continue semantics are covered by cxx_eval_statement_list. */
static tree
cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
bool allow_non_constant,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
tree body = TREE_OPERAND (t, 0);
while (true)
{
cxx_eval_statement_list (ctx, body, allow_non_constant,
non_constant_p, overflow_p, jump_target);
if (returns (jump_target) || breaks (jump_target))
break;
}
if (breaks (jump_target))
*jump_target = NULL_TREE;
return NULL_TREE;
}
/* Evaluate a SWITCH_EXPR for side-effects. Handles switch and break jump
semantics. */
static tree
cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
bool allow_non_constant,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
tree cond = TREE_OPERAND (t, 0);
cond = cxx_eval_constant_expression (ctx, cond, allow_non_constant, false,
non_constant_p, overflow_p, NULL);
VERIFY_CONSTANT (cond);
*jump_target = cond;
tree body = TREE_OPERAND (t, 1);
cxx_eval_statement_list (ctx, body, allow_non_constant,
non_constant_p, overflow_p, jump_target);
if (breaks (jump_target) || switches (jump_target))
*jump_target = NULL_TREE;
return NULL_TREE;
}
/* Attempt to reduce the expression T to a constant value. /* Attempt to reduce the expression T to a constant value.
On failure, issue diagnostic and return error_mark_node. */ On failure, issue diagnostic and return error_mark_node. */
/* FIXME unify with c_fully_fold */ /* FIXME unify with c_fully_fold */
...@@ -2584,7 +2751,8 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, ...@@ -2584,7 +2751,8 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
static tree static tree
cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr, bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{ {
constexpr_ctx new_ctx; constexpr_ctx new_ctx;
tree r = t; tree r = t;
...@@ -2639,6 +2807,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2639,6 +2807,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case FUNCTION_DECL: case FUNCTION_DECL:
case TEMPLATE_DECL: case TEMPLATE_DECL:
case LABEL_DECL: case LABEL_DECL:
case LABEL_EXPR:
case CASE_LABEL_EXPR:
return t; return t;
case PARM_DECL: case PARM_DECL:
...@@ -2683,7 +2853,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2683,7 +2853,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
{ {
init = cxx_eval_constant_expression (ctx, init, init = cxx_eval_constant_expression (ctx, init,
allow_non_constant, false, allow_non_constant, false,
non_constant_p, overflow_p); non_constant_p, overflow_p,
NULL);
ctx->values->put (r, init); ctx->values->put (r, init);
} }
else if (ctx == &new_ctx) else if (ctx == &new_ctx)
...@@ -2721,7 +2892,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2721,7 +2892,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
initialization of a temporary. */ initialization of a temporary. */
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, false, allow_non_constant, false,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
if (!*non_constant_p) if (!*non_constant_p)
/* Adjust the type of the result to the type of the temporary. */ /* Adjust the type of the result to the type of the temporary. */
r = adjust_temp_type (TREE_TYPE (t), r); r = adjust_temp_type (TREE_TYPE (t), r);
...@@ -2734,7 +2905,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2734,7 +2905,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
not the side-effect of the initialization. */ not the side-effect of the initialization. */
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, false, allow_non_constant, false,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
break; break;
} }
/* else fall through */ /* else fall through */
...@@ -2746,10 +2917,16 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2746,10 +2917,16 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case SCOPE_REF: case SCOPE_REF:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p, NULL);
break; break;
case RETURN_EXPR: case RETURN_EXPR:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
allow_non_constant, addr,
non_constant_p, overflow_p, NULL);
*jump_target = t;
break;
case NON_LVALUE_EXPR: case NON_LVALUE_EXPR:
case TRY_CATCH_EXPR: case TRY_CATCH_EXPR:
case CLEANUP_POINT_EXPR: case CLEANUP_POINT_EXPR:
...@@ -2759,7 +2936,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2759,7 +2936,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case EH_SPEC_BLOCK: case EH_SPEC_BLOCK:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
jump_target);
break; break;
/* These differ from cxx_eval_unary_expression in that this doesn't /* These differ from cxx_eval_unary_expression in that this doesn't
...@@ -2776,7 +2954,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2776,7 +2954,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
tree op = cxx_eval_constant_expression (ctx, oldop, tree op = cxx_eval_constant_expression (ctx, oldop,
allow_non_constant, allow_non_constant,
/*addr*/true, /*addr*/true,
non_constant_p, overflow_p); non_constant_p, overflow_p,
NULL);
/* Don't VERIFY_CONSTANT here. */ /* Don't VERIFY_CONSTANT here. */
if (*non_constant_p) if (*non_constant_p)
return t; return t;
...@@ -2827,15 +3006,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2827,15 +3006,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0)) if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
|| TREE_CODE (op1) == EMPTY_CLASS_EXPR) || TREE_CODE (op1) == EMPTY_CLASS_EXPR)
r = cxx_eval_constant_expression (ctx, op0, allow_non_constant, r = cxx_eval_constant_expression (ctx, op0, allow_non_constant,
addr, non_constant_p, overflow_p); addr, non_constant_p, overflow_p,
jump_target);
else else
{ {
/* Check that the LHS is constant and then discard it. */ /* Check that the LHS is constant and then discard it. */
cxx_eval_constant_expression (ctx, op0, allow_non_constant, cxx_eval_constant_expression (ctx, op0, allow_non_constant,
false, non_constant_p, overflow_p); false, non_constant_p, overflow_p,
jump_target);
op1 = TREE_OPERAND (t, 1); op1 = TREE_OPERAND (t, 1);
r = cxx_eval_constant_expression (ctx, op1, allow_non_constant, r = cxx_eval_constant_expression (ctx, op1, allow_non_constant,
addr, non_constant_p, overflow_p); addr, non_constant_p, overflow_p,
jump_target);
} }
} }
break; break;
...@@ -2929,7 +3111,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2929,7 +3111,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case COND_EXPR: case COND_EXPR:
case VEC_COND_EXPR: case VEC_COND_EXPR:
r = cxx_eval_conditional_expression (ctx, t, allow_non_constant, addr, r = cxx_eval_conditional_expression (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
jump_target);
break; break;
case CONSTRUCTOR: case CONSTRUCTOR:
...@@ -2960,7 +3143,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2960,7 +3143,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
tree oldop = TREE_OPERAND (t, 0); tree oldop = TREE_OPERAND (t, 0);
tree op = cxx_eval_constant_expression (ctx, oldop, tree op = cxx_eval_constant_expression (ctx, oldop,
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
NULL);
if (*non_constant_p) if (*non_constant_p)
return t; return t;
if (POINTER_TYPE_P (TREE_TYPE (t)) if (POINTER_TYPE_P (TREE_TYPE (t))
...@@ -2992,25 +3176,16 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -2992,25 +3176,16 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return t; return t;
case STATEMENT_LIST: case STATEMENT_LIST:
{
new_ctx = *ctx; new_ctx = *ctx;
new_ctx.ctor = new_ctx.object = NULL_TREE; new_ctx.ctor = new_ctx.object = NULL_TREE;
tree_stmt_iterator i; return cxx_eval_statement_list (&new_ctx, t, allow_non_constant,
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) non_constant_p, overflow_p, jump_target);
{
cxx_eval_constant_expression (&new_ctx, tsi_stmt (i),
allow_non_constant, false,
non_constant_p, overflow_p);
if (*non_constant_p)
break;
}
}
break;
case BIND_EXPR: case BIND_EXPR:
return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t), return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t),
allow_non_constant, addr, allow_non_constant, addr,
non_constant_p, overflow_p); non_constant_p, overflow_p,
jump_target);
case PREINCREMENT_EXPR: case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR: case POSTINCREMENT_EXPR:
...@@ -3058,16 +3233,24 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ...@@ -3058,16 +3233,24 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
gcc_assert (same_type_ignoring_top_level_qualifiers_p gcc_assert (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (t), TREE_TYPE (ctor))); (TREE_TYPE (t), TREE_TYPE (ctor)));
return cxx_eval_constant_expression return cxx_eval_constant_expression
(ctx, ctor, allow_non_constant, addr, non_constant_p, overflow_p); (ctx, ctor, allow_non_constant, addr,
non_constant_p, overflow_p, NULL);
} }
break; break;
case GOTO_EXPR: case GOTO_EXPR:
*jump_target = TREE_OPERAND (t, 0);
gcc_assert (breaks (jump_target) || continues (jump_target));
break;
case LOOP_EXPR: case LOOP_EXPR:
cxx_eval_loop_expr (ctx, t, allow_non_constant,
non_constant_p, overflow_p, jump_target);
break;
case SWITCH_EXPR: case SWITCH_EXPR:
if (!allow_non_constant) cxx_eval_switch_expr (ctx, t, allow_non_constant,
sorry ("%qs in constant expression", get_tree_code_name (TREE_CODE (t))); non_constant_p, overflow_p, jump_target);
*non_constant_p = true;
break; break;
default: default:
...@@ -3128,7 +3311,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, ...@@ -3128,7 +3311,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
} }
r = cxx_eval_constant_expression (&ctx, r, allow_non_constant, r = cxx_eval_constant_expression (&ctx, r, allow_non_constant,
false, &non_constant_p, &overflow_p); false, &non_constant_p, &overflow_p, NULL);
verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
...@@ -3205,7 +3388,7 @@ is_sub_constant_expr (tree t) ...@@ -3205,7 +3388,7 @@ is_sub_constant_expr (tree t)
hash_map <tree, tree> map; hash_map <tree, tree> map;
ctx.values = &map; ctx.values = &map;
cxx_eval_constant_expression (&ctx, t, true, false, &non_constant_p, cxx_eval_constant_expression (&ctx, t, true, false, &non_constant_p,
&overflow_p); &overflow_p, NULL);
return !non_constant_p && !overflow_p; return !non_constant_p && !overflow_p;
} }
......
...@@ -74,6 +74,10 @@ begin_bc_block (enum bc_t bc, location_t location) ...@@ -74,6 +74,10 @@ begin_bc_block (enum bc_t bc, location_t location)
tree label = create_artificial_label (location); tree label = create_artificial_label (location);
DECL_CHAIN (label) = bc_label[bc]; DECL_CHAIN (label) = bc_label[bc];
bc_label[bc] = label; bc_label[bc] = label;
if (bc == bc_break)
LABEL_DECL_BREAK (label) = true;
else
LABEL_DECL_CONTINUE (label) = true;
return label; return label;
} }
......
...@@ -148,12 +148,14 @@ c-common.h, not after. ...@@ -148,12 +148,14 @@ c-common.h, not after.
DECL_LOCAL_FUNCTION_P (in FUNCTION_DECL) DECL_LOCAL_FUNCTION_P (in FUNCTION_DECL)
DECL_MUTABLE_P (in FIELD_DECL) DECL_MUTABLE_P (in FIELD_DECL)
DECL_DEPENDENT_P (in USING_DECL) DECL_DEPENDENT_P (in USING_DECL)
LABEL_DECL_BREAK (in LABEL_DECL)
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL). 1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL) DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL) DECL_MEMBER_TEMPLATE_P (in TEMPLATE_DECL)
USING_DECL_TYPENAME_P (in USING_DECL) USING_DECL_TYPENAME_P (in USING_DECL)
DECL_VLA_CAPTURE_P (in FIELD_DECL) DECL_VLA_CAPTURE_P (in FIELD_DECL)
DECL_ARRAY_PARAMETER_P (in PARM_DECL) DECL_ARRAY_PARAMETER_P (in PARM_DECL)
LABEL_DECL_CONTINUE (in LABEL_DECL)
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL). 2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL) DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
3: DECL_IN_AGGR_P. 3: DECL_IN_AGGR_P.
...@@ -3243,6 +3245,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -3243,6 +3245,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define DECL_LOCAL_FUNCTION_P(NODE) \ #define DECL_LOCAL_FUNCTION_P(NODE) \
DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE)) DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE))
/* Nonzero if NODE is the target for genericization of 'break' stmts. */
#define LABEL_DECL_BREAK(NODE) \
DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE))
/* Nonzero if NODE is the target for genericization of 'continue' stmts. */
#define LABEL_DECL_CONTINUE(NODE) \
DECL_LANG_FLAG_1 (LABEL_DECL_CHECK (NODE))
/* True if NODE was declared with auto in its return type, but it has /* True if NODE was declared with auto in its return type, but it has
started compilation and so the return type might have been changed by started compilation and so the return type might have been changed by
return type deduction; its declared return type should be found in return type deduction; its declared return type should be found in
......
// { dg-do compile { target c++14 } }
constexpr int f (int i)
{
int j = 0;
for (; i > 0; --i)
++j;
return j;
}
constexpr int i = f(42);
#define SA(X) static_assert((X),#X)
SA(i==42);
// { dg-do compile { target c++14 } }
constexpr int f (int i)
{
return 24;
return 36;
}
constexpr int i = f(42);
#define SA(X) static_assert((X),#X)
SA(i==24);
// { dg-do compile { target c++14 } }
constexpr int f (int i)
{
}
constexpr int i = f(42); // { dg-error "flows off the end" }
// { dg-do compile { target c++14 } }
constexpr int f (int i)
{
switch (i)
{
case 1:
return 42;
default:
return 0;
}
}
constexpr int i = f(1);
#define SA(X) static_assert((X),#X)
SA(i==42);
// { dg-do compile { target c++14 } }
constexpr int f (int i)
{
int j = 0;
switch (i)
{
case 1:
j = 42;
break;
default:
j = 24;
break;
}
return j;
}
constexpr int i = f(1);
#define SA(X) static_assert((X),#X)
SA(i==42);
// { dg-do compile { target c++14 } }
constexpr int f (int i)
{
int j = 0;
switch (i)
{
case 1:
j = 42;
break;
default:
j = 24;
break;
}
return j;
}
constexpr int i = f(2);
#define SA(X) static_assert((X),#X)
SA(i==24);
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