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
This commit is contained in:
parent
92a596e856
commit
12d9ce1903
@ -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.
|
||||
|
@ -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,
|
||||
|
22
gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C
Normal file
22
gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C
Normal file
@ -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, "");
|
||||
}
|
12
gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C
Normal file
12
gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C
Normal file
@ -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,"");
|
Loading…
Reference in New Issue
Block a user