Well-formed C++14 code with a loop in a constexpr function works fine,
but we were crashing while trying to diagnose an unsuitable constexpr
function because potential_constant_expression_1 didn't understand loops.
The second patch improves constexpr handling of EXIT_EXPR and loops
around COMPOUND_EXPR rather than STATEMENT_LIST. This is not currently
necessary, but might be in future.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit e9df0f90c8502653b06a100bef9c765d6ee52ca9
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Mar 3 08:15:50 2016 -0600
PR c++/68206
PR c++/68530
* constexpr.c (potential_constant_expression_1): Handle LOOP_EXPR
and GOTO_EXPR.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index ae0c973..d508660 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4924,6 +4924,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
case NON_DEPENDENT_EXPR:
/* For convenience. */
case RETURN_EXPR:
+ case LOOP_EXPR:
+ case EXIT_EXPR:
return RECUR (TREE_OPERAND (t, 0), want_rval);
case TRY_FINALLY_EXPR:
@@ -5135,6 +5137,15 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
case EMPTY_CLASS_EXPR:
return false;
+ case GOTO_EXPR:
+ {
+ tree *target = &TREE_OPERAND (t, 0);
+ /* Gotos representing break and continue are OK; we should have
+ rejected other gotos in parsing. */
+ gcc_assert (breaks (target) || continues (target));
+ return true;
+ }
+
default:
if (objc_is_property_ref (t))
return false;
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-loop5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop5.C
new file mode 100644
index 0000000..02f372d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop5.C
@@ -0,0 +1,19 @@
+// PR c++/68530
+// { dg-do compile { target c++14 } }
+
+struct thing {
+ void foo() {}
+};
+
+template<typename>
+constexpr int count()
+{
+ auto item = thing {};
+ for(; (item.foo(), false);); // { dg-error "foo" }
+ return 0;
+}
+
+int main()
+{
+ static_assert( count<int>() == 0, "" ); // { dg-error "" }
+}
commit 0e632adeb8c2253f6a9f9e4445c577eef51b1f4c
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Apr 19 13:59:05 2016 -0400
Improve constexpr handling of other loop forms.
* constexpr.c (breaks): Handle EXIT_EXPR.
(cxx_eval_loop_expr): Handle COMPOUND_EXPR body.
(cxx_eval_constant_expression): Handle EXIT_EXPR, improve handling
of COMPOUND_EXPR.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index d508660..41f0b5c 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -3241,8 +3241,9 @@ static bool
breaks (tree *jump_target)
{
return *jump_target
- && TREE_CODE (*jump_target) == LABEL_DECL
- && LABEL_DECL_BREAK (*jump_target);
+ && ((TREE_CODE (*jump_target) == LABEL_DECL
+ && LABEL_DECL_BREAK (*jump_target))
+ || TREE_CODE (*jump_target) == EXIT_EXPR);
}
static bool
@@ -3358,8 +3359,8 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
hash_set<tree> save_exprs;
new_ctx.save_exprs = &save_exprs;
- cxx_eval_statement_list (&new_ctx, body,
- non_constant_p, overflow_p, jump_target);
+ cxx_eval_constant_expression (&new_ctx, body, /*lval*/false,
+ non_constant_p, overflow_p, jump_target);
/* Forget saved values of SAVE_EXPRs. */
for (hash_set<tree>::iterator iter = save_exprs.begin();
@@ -3750,6 +3751,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
cxx_eval_constant_expression (ctx, op0,
true, non_constant_p, overflow_p,
jump_target);
+ if (*non_constant_p)
+ return t;
op1 = TREE_OPERAND (t, 1);
r = cxx_eval_constant_expression (ctx, op1,
lval, non_constant_p, overflow_p,
@@ -4015,6 +4018,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
}
break;
+ case EXIT_EXPR:
+ {
+ tree cond = TREE_OPERAND (t, 0);
+ cond = cxx_eval_constant_expression (ctx, cond, /*lval*/false,
+ non_constant_p, overflow_p);
+ VERIFY_CONSTANT (cond);
+ if (integer_nonzerop (cond))
+ *jump_target = t;
+ }
+ break;
+
case GOTO_EXPR:
*jump_target = TREE_OPERAND (t, 0);
gcc_assert (breaks (jump_target) || continues (jump_target));