aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2014-12-17 15:41:18 -0500
committerJason Merrill <jason@gcc.gnu.org>2014-12-17 15:41:18 -0500
commit12d9ce19034428072b3779eff017c5e129ee4c0e (patch)
treedfc5f8c7bb2b4b522da4a02ec8e17658f3a656ab
parent92a596e856e165a28c245fcc29e72baf8283cf9c (diff)
downloadgcc-12d9ce19034428072b3779eff017c5e129ee4c0e.zip
gcc-12d9ce19034428072b3779eff017c5e129ee4c0e.tar.gz
gcc-12d9ce19034428072b3779eff017c5e129ee4c0e.tar.bz2
re PR c++/64333 (C++14 constexpr gives wrong results when a looping constexpr function is evaluated twice)
PR c++/64333 * constexpr.c (cxx_bind_parameters_in_call): non_constant_args parm. (cxx_eval_call_expression): Don't cache calls with non-constant args. (cxx_eval_constant_expression) [COMPOUND_EXPR]: Pass true for lval. (cxx_eval_unary_expression, cxx_eval_binary_expression) (cxx_eval_conditional_expression): Pass false for lval. From-SVN: r218832
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/constexpr.c89
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C12
4 files changed, 89 insertions, 41 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 8adf2a1..e7e2365 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,12 @@
2014-12-17 Jason Merrill <jason@redhat.com>
+ PR c++/64333
+ * constexpr.c (cxx_bind_parameters_in_call): non_constant_args parm.
+ (cxx_eval_call_expression): Don't cache calls with non-constant args.
+ (cxx_eval_constant_expression) [COMPOUND_EXPR]: Pass true for lval.
+ (cxx_eval_unary_expression, cxx_eval_binary_expression)
+ (cxx_eval_conditional_expression): Pass false for lval.
+
* constexpr.c: Change "addr" parm names to "lval".
* constexpr.c: Tweak comments and formatting.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 3ab80f7..afbcf51 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1050,7 +1050,8 @@ adjust_temp_type (tree type, tree temp)
static void
cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
constexpr_call *new_call,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ bool *non_constant_args)
{
const int nargs = call_expr_nargs (t);
tree fun = new_call->fundef->decl;
@@ -1099,6 +1100,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
/* Make sure the binding has the same type as the parm. */
if (TREE_CODE (type) != REFERENCE_TYPE)
arg = adjust_temp_type (type, arg);
+ if (!TREE_CONSTANT (arg))
+ *non_constant_args = true;
*p = build_tree_list (parms, arg);
p = &TREE_CHAIN (*p);
next:
@@ -1155,10 +1158,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
{
location_t loc = EXPR_LOC_OR_LOC (t, input_location);
tree fun = get_function_named_in_call (t);
- tree result;
constexpr_call new_call = { NULL, NULL, NULL, 0 };
- constexpr_call **slot;
- constexpr_call *entry;
bool depth_ok;
if (fun == NULL_TREE)
@@ -1264,36 +1264,45 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
ctx = &new_ctx;
}
+ bool non_constant_args = false;
cxx_bind_parameters_in_call (ctx, t, &new_call,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, &non_constant_args);
if (*non_constant_p)
return t;
depth_ok = push_cx_call_context (t);
- new_call.hash
- = iterative_hash_template_arg (new_call.bindings,
- constexpr_fundef_hasher::hash (new_call.fundef));
+ tree result = NULL_TREE;
- /* If we have seen this call before, we are done. */
- maybe_initialize_constexpr_call_table ();
- slot = constexpr_call_table->find_slot (&new_call, INSERT);
- entry = *slot;
- if (entry == NULL)
+ constexpr_call *entry = NULL;
+ if (!non_constant_args)
{
- /* We need to keep a pointer to the entry, not just the slot, as the
- slot can move in the call to cxx_eval_builtin_function_call. */
- *slot = entry = ggc_alloc<constexpr_call> ();
- *entry = new_call;
- }
- /* Calls which are in progress have their result set to NULL
- so that we can detect circular dependencies. */
- else if (entry->result == NULL)
- {
- if (!ctx->quiet)
- error ("call has circular dependency");
- *non_constant_p = true;
- entry->result = result = error_mark_node;
+ new_call.hash = iterative_hash_template_arg
+ (new_call.bindings, constexpr_fundef_hasher::hash (new_call.fundef));
+
+ /* If we have seen this call before, we are done. */
+ maybe_initialize_constexpr_call_table ();
+ constexpr_call **slot
+ = constexpr_call_table->find_slot (&new_call, INSERT);
+ entry = *slot;
+ if (entry == NULL)
+ {
+ /* We need to keep a pointer to the entry, not just the slot, as the
+ slot can move in the call to cxx_eval_builtin_function_call. */
+ *slot = entry = ggc_alloc<constexpr_call> ();
+ *entry = new_call;
+ }
+ /* Calls which are in progress have their result set to NULL
+ so that we can detect circular dependencies. */
+ else if (entry->result == NULL)
+ {
+ if (!ctx->quiet)
+ error ("call has circular dependency");
+ *non_constant_p = true;
+ entry->result = result = error_mark_node;
+ }
+ else
+ result = entry->result;
}
if (!depth_ok)
@@ -1303,11 +1312,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
"-fconstexpr-depth= to increase the maximum)",
max_constexpr_depth);
*non_constant_p = true;
- entry->result = result = error_mark_node;
+ result = error_mark_node;
}
else
{
- result = entry->result;
if (!result || result == error_mark_node)
{
if (!use_new_call)
@@ -1395,7 +1403,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
if (result == error_mark_node)
*non_constant_p = true;
if (*non_constant_p)
- entry->result = result = error_mark_node;
+ result = error_mark_node;
else if (result)
{
/* If this was a call to initialize an object, set the type of
@@ -1409,10 +1417,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
result = adjust_temp_type (TREE_TYPE (TREE_TYPE (ob_arg)),
result);
}
- entry->result = result;
}
else
result = void_node;
+ if (entry)
+ entry->result = result;
}
pop_cx_call_context ();
@@ -1558,13 +1567,13 @@ cxx_eval_check_shift_p (location_t loc, const constexpr_ctx *ctx,
static tree
cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
- bool lval,
+ bool /*lval*/,
bool *non_constant_p, bool *overflow_p)
{
tree r;
tree orig_arg = TREE_OPERAND (t, 0);
- tree arg = cxx_eval_constant_expression (ctx, orig_arg,
- lval, non_constant_p, overflow_p);
+ tree arg = cxx_eval_constant_expression (ctx, orig_arg, /*lval*/false,
+ non_constant_p, overflow_p);
VERIFY_CONSTANT (arg);
location_t loc = EXPR_LOCATION (t);
enum tree_code code = TREE_CODE (t);
@@ -1586,19 +1595,17 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
- bool lval,
+ bool /*lval*/,
bool *non_constant_p, bool *overflow_p)
{
tree r;
tree orig_lhs = TREE_OPERAND (t, 0);
tree orig_rhs = TREE_OPERAND (t, 1);
tree lhs, rhs;
- lhs = cxx_eval_constant_expression (ctx, orig_lhs,
- lval,
+ lhs = cxx_eval_constant_expression (ctx, orig_lhs, /*lval*/false,
non_constant_p, overflow_p);
VERIFY_CONSTANT (lhs);
- rhs = cxx_eval_constant_expression (ctx, orig_rhs,
- lval,
+ rhs = cxx_eval_constant_expression (ctx, orig_rhs, /*lval*/false,
non_constant_p, overflow_p);
VERIFY_CONSTANT (rhs);
@@ -1630,7 +1637,7 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
tree *jump_target)
{
tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
- lval,
+ /*lval*/false,
non_constant_p, overflow_p);
VERIFY_CONSTANT (val);
/* Don't VERIFY_CONSTANT the other operands. */
@@ -3085,7 +3092,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = *p;
else
{
- r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), addr,
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false,
non_constant_p, overflow_p);
ctx->values->put (t, r);
}
@@ -3174,7 +3181,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
{
/* Check that the LHS is constant and then discard it. */
cxx_eval_constant_expression (ctx, op0,
- false, non_constant_p, overflow_p,
+ true, non_constant_p, overflow_p,
jump_target);
op1 = TREE_OPERAND (t, 1);
r = cxx_eval_constant_expression (ctx, op1,
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C
new file mode 100644
index 0000000..bdef8a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C
@@ -0,0 +1,22 @@
+// PR c++/64333
+// { dg-do compile { target c++14 } }
+#include <initializer_list>
+
+constexpr int max(std::initializer_list<int> ints)
+{
+ int ret = *(ints.begin());
+ for (int i = 0; i < ints.size(); ++i) {
+ if (*(ints.begin()+i) > ret) {
+ ret = *(ints.begin()+i);
+ }
+ }
+ return ret;
+}
+
+int main()
+{
+ constexpr int z = max({7,6,5,4,3,2,1});
+ constexpr int z2 = max({5,4,3,2,1});
+ static_assert(z == 7, "");
+ static_assert(z2 == 5, "");
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C
new file mode 100644
index 0000000..2e53e48
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f(int* p) { return *p; }
+constexpr int g(int n)
+{
+ int sum = 0;
+ for (int i = 1; i <= n; ++i)
+ sum += f(&i);
+ return sum;
+}
+
+static_assert(g(3) == 3+2+1,"");