struct check_for_return_continue_data {
hash_set<tree> *pset;
tree continue_stmt;
+ tree break_stmt;
};
/* Helper function for potential_constant_expression_1 SWITCH_STMT handling,
called through cp_walk_tree. Return the first RETURN_EXPR found, or note
- the first CONTINUE_STMT if RETURN_EXPR is not found. */
+ the first CONTINUE_STMT and/or BREAK_STMT if RETURN_EXPR is not found. */
static tree
check_for_return_continue (tree *tp, int *walk_subtrees, void *data)
{
- tree t = *tp, s;
+ tree t = *tp, s, b;
check_for_return_continue_data *d = (check_for_return_continue_data *) data;
switch (TREE_CODE (t))
{
d->continue_stmt = t;
break;
+ case BREAK_STMT:
+ if (d->break_stmt == NULL_TREE)
+ d->break_stmt = t;
+ break;
+
#define RECUR(x) \
if (tree r = cp_walk_tree (&x, check_for_return_continue, data, \
d->pset)) \
*walk_subtrees = 0;
RECUR (DO_COND (t));
s = d->continue_stmt;
+ b = d->break_stmt;
RECUR (DO_BODY (t));
d->continue_stmt = s;
+ d->break_stmt = b;
break;
case WHILE_STMT:
*walk_subtrees = 0;
RECUR (WHILE_COND (t));
s = d->continue_stmt;
+ b = d->break_stmt;
RECUR (WHILE_BODY (t));
d->continue_stmt = s;
+ d->break_stmt = b;
break;
case FOR_STMT:
RECUR (FOR_COND (t));
RECUR (FOR_EXPR (t));
s = d->continue_stmt;
+ b = d->break_stmt;
RECUR (FOR_BODY (t));
d->continue_stmt = s;
+ d->break_stmt = b;
break;
case RANGE_FOR_STMT:
*walk_subtrees = 0;
RECUR (RANGE_FOR_EXPR (t));
s = d->continue_stmt;
+ b = d->break_stmt;
RECUR (RANGE_FOR_BODY (t));
d->continue_stmt = s;
+ d->break_stmt = b;
+ break;
+
+ case SWITCH_STMT:
+ *walk_subtrees = 0;
+ RECUR (SWITCH_STMT_COND (t));
+ b = d->break_stmt;
+ RECUR (SWITCH_STMT_BODY (t));
+ d->break_stmt = b;
break;
#undef RECUR
/* If we couldn't evaluate the condition, it might not ever be
true. */
if (!integer_onep (tmp))
- return true;
+ {
+ /* Before returning true, check if the for body can contain
+ a return. */
+ hash_set<tree> pset;
+ check_for_return_continue_data data = { &pset, NULL_TREE,
+ NULL_TREE };
+ if (tree ret_expr
+ = cp_walk_tree (&FOR_BODY (t), check_for_return_continue,
+ &data, &pset))
+ *jump_target = ret_expr;
+ return true;
+ }
}
if (!RECUR (FOR_EXPR (t), any))
return false;
tmp = cxx_eval_outermost_constant_expr (tmp, true);
/* If we couldn't evaluate the condition, it might not ever be true. */
if (!integer_onep (tmp))
- return true;
+ {
+ /* Before returning true, check if the while body can contain
+ a return. */
+ hash_set<tree> pset;
+ check_for_return_continue_data data = { &pset, NULL_TREE,
+ NULL_TREE };
+ if (tree ret_expr
+ = cp_walk_tree (&WHILE_BODY (t), check_for_return_continue,
+ &data, &pset))
+ *jump_target = ret_expr;
+ return true;
+ }
if (!RECUR (WHILE_BODY (t), any))
return false;
if (breaks (jump_target) || continues (jump_target))
else
{
hash_set<tree> pset;
- check_for_return_continue_data data = { &pset, NULL_TREE };
+ check_for_return_continue_data data = { &pset, NULL_TREE,
+ NULL_TREE };
if (tree ret_expr
= cp_walk_tree (&SWITCH_STMT_BODY (t), check_for_return_continue,
&data, &pset))
return RECUR (TREE_OPERAND (t, 2), want_rval);
else if (TREE_CODE (tmp) == INTEGER_CST)
return RECUR (TREE_OPERAND (t, 1), want_rval);
+ tmp = *jump_target;
for (i = 1; i < 3; ++i)
- if (potential_constant_expression_1 (TREE_OPERAND (t, i),
- want_rval, strict, now,
- tf_none, jump_target))
- return true;
+ {
+ tree this_jump_target = tmp;
+ if (potential_constant_expression_1 (TREE_OPERAND (t, i),
+ want_rval, strict, now,
+ tf_none, &this_jump_target))
+ {
+ if (returns (&this_jump_target))
+ *jump_target = this_jump_target;
+ else if (!returns (jump_target))
+ {
+ if (breaks (&this_jump_target)
+ || continues (&this_jump_target))
+ *jump_target = this_jump_target;
+ if (i == 1)
+ {
+ /* If the then branch is potentially constant, but
+ does not return, check if the else branch
+ couldn't return, break or continue. */
+ hash_set<tree> pset;
+ check_for_return_continue_data data = { &pset, NULL_TREE,
+ NULL_TREE };
+ if (tree ret_expr
+ = cp_walk_tree (&TREE_OPERAND (t, 2),
+ check_for_return_continue, &data,
+ &pset))
+ *jump_target = ret_expr;
+ else if (*jump_target == NULL_TREE)
+ {
+ if (data.continue_stmt)
+ *jump_target = data.continue_stmt;
+ else if (data.break_stmt)
+ *jump_target = data.break_stmt;
+ }
+ }
+ }
+ return true;
+ }
+ }
if (flags & tf_error)
error_at (loc, "expression %qE is not a constant expression", t);
return false;