diff options
author | Jason Merrill <jason@redhat.com> | 2014-12-17 15:41:18 -0500 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2014-12-17 15:41:18 -0500 |
commit | 12d9ce19034428072b3779eff017c5e129ee4c0e (patch) | |
tree | dfc5f8c7bb2b4b522da4a02ec8e17658f3a656ab | |
parent | 92a596e856e165a28c245fcc29e72baf8283cf9c (diff) | |
download | gcc-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/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 89 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C | 12 |
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,""); |