Now that in C++14 we can have non-constant arguments to constexpr
functions called from another constexpr function, we need to avoid
caching the result, as a later call might produce a different value for
the same non-constant argument, e.g. the address of a local variable.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit f702ac694e3d7e59453d5fc494d81cbfdab9a88c
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Dec 17 10:19:28 2014 -0500
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.
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,"");
commit 0b751ac9d5dc1bc85349566669be1b5839757041
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Dec 17 13:30:20 2014 -0500
* constexpr.c: Change "addr" parm names to "lval".
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 1323111..3ab80f7 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -999,7 +999,7 @@ lookup_parameter_binding (const constexpr_call *call, tree t)
static tree
cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
const int nargs = call_expr_nargs (t);
@@ -1009,7 +1009,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t,
for (i = 0; i < nargs; ++i)
{
args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, i),
- addr,
+ lval,
non_constant_p, overflow_p);
if (ctx->quiet && *non_constant_p)
return t;
@@ -1071,7 +1071,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
x = ctx->object;
x = cp_build_addr_expr (x, tf_warning_or_error);
}
- bool addr = false;
+ bool lval = false;
if (parms && DECL_BY_REFERENCE (parms) && !use_new_call)
{
/* cp_genericize made this a reference for argument passing, but
@@ -1082,9 +1082,9 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
gcc_assert (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE);
type = TREE_TYPE (type);
x = convert_from_reference (x);
- addr = true;
+ lval = true;
}
- arg = cxx_eval_constant_expression (ctx, x, addr,
+ arg = cxx_eval_constant_expression (ctx, x, lval,
non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p && ctx->quiet)
@@ -1150,7 +1150,7 @@ cx_error_context (void)
static tree
cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
location_t loc = EXPR_LOC_OR_LOC (t, input_location);
@@ -1178,7 +1178,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
{
/* Might be a constexpr function pointer. */
fun = cxx_eval_constant_expression (ctx, fun,
- /*addr*/false, non_constant_p,
+ /*lval*/false, non_constant_p,
overflow_p);
STRIP_NOPS (fun);
if (TREE_CODE (fun) == ADDR_EXPR)
@@ -1200,7 +1200,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
if (is_builtin_fn (fun))
return cxx_eval_builtin_function_call (ctx, t,
- addr, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p);
if (!DECL_DECLARED_CONSTEXPR_P (fun))
{
if (!ctx->quiet)
@@ -1219,7 +1219,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
{
tree arg = convert_from_reference (get_nth_callarg (t, 1));
return cxx_eval_constant_expression (ctx, arg,
- addr, non_constant_p,
+ lval, non_constant_p,
overflow_p);
}
else if (TREE_CODE (t) == AGGR_INIT_EXPR
@@ -1315,7 +1315,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
new_ctx.call = &new_call;
result = (cxx_eval_constant_expression
(&new_ctx, new_call.fundef->body,
- addr,
+ lval,
non_constant_p, overflow_p));
}
else
@@ -1358,7 +1358,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
tree jump_target = NULL_TREE;
cxx_eval_constant_expression (ctx, body,
- addr, non_constant_p, overflow_p,
+ lval, non_constant_p, overflow_p,
&jump_target);
if (DECL_CONSTRUCTOR_P (fun))
@@ -1367,7 +1367,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
side-effects rather than the value. We could get at the
value by evaluating *this, but we don't bother; there's
no need to put such a call in the hash table. */
- result = addr ? ctx->object : ctx->ctor;
+ result = lval ? ctx->object : ctx->ctor;
else
{
result = *ctx->values->get (slot ? slot : res);
@@ -1558,13 +1558,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 addr,
+ 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,
- addr, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p);
VERIFY_CONSTANT (arg);
location_t loc = EXPR_LOCATION (t);
enum tree_code code = TREE_CODE (t);
@@ -1586,7 +1586,7 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
tree r;
@@ -1594,11 +1594,11 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
tree orig_rhs = TREE_OPERAND (t, 1);
tree lhs, rhs;
lhs = cxx_eval_constant_expression (ctx, orig_lhs,
- addr,
+ lval,
non_constant_p, overflow_p);
VERIFY_CONSTANT (lhs);
rhs = cxx_eval_constant_expression (ctx, orig_rhs,
- addr,
+ lval,
non_constant_p, overflow_p);
VERIFY_CONSTANT (rhs);
@@ -1625,22 +1625,22 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
- addr,
+ lval,
non_constant_p, overflow_p);
VERIFY_CONSTANT (val);
/* Don't VERIFY_CONSTANT the other operands. */
if (integer_zerop (val))
return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
- addr,
+ lval,
non_constant_p, overflow_p,
jump_target);
return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
- addr,
+ lval,
non_constant_p, overflow_p,
jump_target);
}
@@ -1650,12 +1650,12 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
tree oldary = TREE_OPERAND (t, 0);
tree ary = cxx_eval_constant_expression (ctx, oldary,
- addr,
+ lval,
non_constant_p, overflow_p);
tree index, oldidx;
HOST_WIDE_INT i;
@@ -1668,9 +1668,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
false,
non_constant_p, overflow_p);
VERIFY_CONSTANT (index);
- if (addr && ary == oldary && index == oldidx)
+ if (lval && ary == oldary && index == oldidx)
return t;
- else if (addr)
+ else if (lval)
return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
elem_type = TREE_TYPE (TREE_TYPE (ary));
if (TREE_CODE (ary) == CONSTRUCTOR)
@@ -1696,7 +1696,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
initializer, it's value-initialized. */
tree val = build_value_init (elem_type, tf_warning_or_error);
return cxx_eval_constant_expression (ctx, val,
- addr,
+ lval,
non_constant_p, overflow_p);
}
@@ -1733,7 +1733,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
unsigned HOST_WIDE_INT i;
@@ -1742,11 +1742,11 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
tree part = TREE_OPERAND (t, 1);
tree orig_whole = TREE_OPERAND (t, 0);
tree whole = cxx_eval_constant_expression (ctx, orig_whole,
- addr,
+ lval,
non_constant_p, overflow_p);
if (whole == orig_whole)
return t;
- if (addr)
+ if (lval)
return fold_build3 (COMPONENT_REF, TREE_TYPE (t),
whole, part, NULL_TREE);
/* Don't VERIFY_CONSTANT here; we only want to check that we got a
@@ -1801,7 +1801,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
/* If there's no explicit init for this field, it's value-initialized. */
value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
return cxx_eval_constant_expression (ctx, value,
- addr,
+ lval,
non_constant_p, overflow_p);
}
@@ -1811,7 +1811,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
tree orig_whole = TREE_OPERAND (t, 0);
@@ -1819,7 +1819,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
bool fld_seen = false;
HOST_WIDE_INT istart, isize;
tree whole = cxx_eval_constant_expression (ctx, orig_whole,
- addr,
+ lval,
non_constant_p, overflow_p);
tree start, field, value;
unsigned HOST_WIDE_INT i;
@@ -1897,19 +1897,19 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t,
tree bailout_value, tree continue_value,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
tree r;
tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
- addr,
+ lval,
non_constant_p, overflow_p);
VERIFY_CONSTANT (lhs);
if (tree_int_cst_equal (lhs, bailout_value))
return lhs;
gcc_assert (tree_int_cst_equal (lhs, continue_value));
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
- addr, non_constant_p,
+ lval, non_constant_p,
overflow_p);
VERIFY_CONSTANT (r);
return r;
@@ -2031,7 +2031,7 @@ verify_ctor_sanity (const constexpr_ctx *ctx, tree type)
static tree
cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t);
@@ -2052,7 +2052,7 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
initializers can refer to it. */
CONSTRUCTOR_APPEND_ELT (*p, index, new_ctx.ctor);
tree elt = cxx_eval_constant_expression (&new_ctx, value,
- addr,
+ lval,
non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT here. */
if (ctx->quiet && *non_constant_p)
@@ -2111,7 +2111,7 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
- bool value_init, bool addr,
+ bool value_init, bool lval,
bool *non_constant_p, bool *overflow_p)
{
tree elttype = TREE_TYPE (atype);
@@ -2162,7 +2162,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
eltinit = cp_build_array_ref (input_location, init, idx,
tf_warning_or_error);
eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, value_init,
- addr,
+ lval,
non_constant_p, overflow_p);
}
else if (pre_init)
@@ -2171,7 +2171,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
we just pre-built above. */
eltinit = (cxx_eval_constant_expression
(&new_ctx, init,
- addr, non_constant_p, overflow_p));
+ lval, non_constant_p, overflow_p));
}
else
{
@@ -2184,7 +2184,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
eltinit = move (eltinit);
eltinit = force_rvalue (eltinit, tf_warning_or_error);
eltinit = (cxx_eval_constant_expression
- (&new_ctx, eltinit, addr,
+ (&new_ctx, eltinit, lval,
non_constant_p, overflow_p));
}
if (*non_constant_p && !ctx->quiet)
@@ -2209,14 +2209,14 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
static tree
cxx_eval_vec_init (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
tree atype = TREE_TYPE (t);
tree init = VEC_INIT_EXPR_INIT (t);
tree r = cxx_eval_vec_init_1 (ctx, atype, init,
VEC_INIT_EXPR_VALUE_INIT (t),
- addr, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p);
if (*non_constant_p)
return t;
else
@@ -2416,12 +2416,12 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base)
static tree
cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
tree orig_op0 = TREE_OPERAND (t, 0);
tree op0 = cxx_eval_constant_expression (ctx, orig_op0,
- /*addr*/false, non_constant_p,
+ /*lval*/false, non_constant_p,
overflow_p);
bool empty_base = false;
tree r;
@@ -2435,7 +2435,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
if (r)
r = cxx_eval_constant_expression (ctx, r,
- addr, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p);
else
{
tree sub = op0;
@@ -2459,7 +2459,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
/* If we're pulling out the value of an empty base, make sure
that the whole object is constant and then return an empty
CONSTRUCTOR. */
- if (empty_base && !addr)
+ if (empty_base && !lval)
{
VERIFY_CONSTANT (r);
r = build_constructor (TREE_TYPE (t), NULL);
@@ -2468,9 +2468,9 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
if (r == NULL_TREE)
{
- if (addr && op0 != orig_op0)
+ if (lval && op0 != orig_op0)
return build1 (INDIRECT_REF, TREE_TYPE (t), op0);
- if (!addr)
+ if (!lval)
VERIFY_CONSTANT (t);
return t;
}
@@ -2526,7 +2526,7 @@ non_const_var_error (tree r)
static tree
cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
int i;
@@ -2536,7 +2536,7 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
for (i = 0; i < 3; i++)
{
args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i),
- addr,
+ lval,
non_constant_p, overflow_p);
VERIFY_CONSTANT (args[i]);
}
@@ -2561,7 +2561,7 @@ var_in_constexpr_fn (tree t)
static tree
cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
constexpr_ctx new_ctx = *ctx;
@@ -2658,7 +2658,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (*non_constant_p)
return t;
- else if (addr)
+ else if (lval)
return target;
else
return init;
@@ -2668,7 +2668,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p)
{
enum tree_code code = TREE_CODE (t);
@@ -2711,7 +2711,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
{
/* Prefix ops are lvalues. */
- if (addr)
+ if (lval)
return op;
else
/* But we optimize when the caller wants an rvalue. */
@@ -2886,7 +2886,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
static tree
cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
- bool addr,
+ bool lval,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
@@ -2913,7 +2913,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
switch (TREE_CODE (t))
{
case RESULT_DECL:
- if (addr)
+ if (lval)
return t;
/* We ask for an rvalue for the RESULT_DECL when indirecting
through an invisible reference. */
@@ -2921,7 +2921,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return (*ctx->values->get (t));
case VAR_DECL:
- if (addr)
+ if (lval)
return t;
/* else fall through. */
case CONST_DECL:
@@ -2954,11 +2954,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (!use_new_call && ctx
&& ctx->call && DECL_CONTEXT (t) == ctx->call->fundef->decl)
r = lookup_parameter_binding (ctx->call, t);
- else if (addr && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
+ else if (lval && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
/* glvalue use. */;
else if (tree *p = ctx->values->get (r))
r = *p;
- else if (addr)
+ else if (lval)
/* Defer in case this is only used for its type. */;
else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
/* Defer, there's no lvalue->rvalue conversion. */;
@@ -2978,7 +2978,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case CALL_EXPR:
case AGGR_INIT_EXPR:
- r = cxx_eval_call_expression (ctx, t, addr,
+ r = cxx_eval_call_expression (ctx, t, lval,
non_constant_p, overflow_p);
break;
@@ -3034,7 +3034,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
ctx->values->put (new_ctx.object, new_ctx.ctor);
ctx = &new_ctx;
}
- /* Pass false for 'addr' because this indicates
+ /* Pass false for 'lval' because this indicates
initialization of a temporary. */
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
false,
@@ -3042,7 +3042,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (!*non_constant_p)
/* Adjust the type of the result to the type of the temporary. */
r = adjust_temp_type (TREE_TYPE (t), r);
- if (addr)
+ if (lval)
{
tree slot = TARGET_EXPR_SLOT (t);
ctx->values->put (slot, r);
@@ -3062,19 +3062,19 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
}
/* else fall through */
case MODIFY_EXPR:
- r = cxx_eval_store_expression (ctx, t, addr,
+ r = cxx_eval_store_expression (ctx, t, lval,
non_constant_p, overflow_p);
break;
case SCOPE_REF:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
- addr,
+ lval,
non_constant_p, overflow_p);
break;
case RETURN_EXPR:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
- addr,
+ lval,
non_constant_p, overflow_p);
*jump_target = t;
break;
@@ -3098,7 +3098,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case EXPR_STMT:
case EH_SPEC_BLOCK:
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
- addr,
+ lval,
non_constant_p, overflow_p,
jump_target);
break;
@@ -3107,7 +3107,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
check for a constant operand or result; an address can be
constant without its operand being, and vice versa. */
case INDIRECT_REF:
- r = cxx_eval_indirect_ref (ctx, t, addr,
+ r = cxx_eval_indirect_ref (ctx, t, lval,
non_constant_p, overflow_p);
break;
@@ -3115,7 +3115,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
{
tree oldop = TREE_OPERAND (t, 0);
tree op = cxx_eval_constant_expression (ctx, oldop,
- /*addr*/true,
+ /*lval*/true,
non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p)
@@ -3138,7 +3138,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case BIT_NOT_EXPR:
case TRUTH_NOT_EXPR:
case FIXED_CONVERT_EXPR:
- r = cxx_eval_unary_expression (ctx, t, addr,
+ r = cxx_eval_unary_expression (ctx, t, lval,
non_constant_p, overflow_p);
break;
@@ -3168,7 +3168,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
|| TREE_CODE (op1) == EMPTY_CLASS_EXPR)
r = cxx_eval_constant_expression (ctx, op0,
- addr, non_constant_p, overflow_p,
+ lval, non_constant_p, overflow_p,
jump_target);
else
{
@@ -3178,7 +3178,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
jump_target);
op1 = TREE_OPERAND (t, 1);
r = cxx_eval_constant_expression (ctx, op1,
- addr, non_constant_p, overflow_p,
+ lval, non_constant_p, overflow_p,
jump_target);
}
}
@@ -3223,7 +3223,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case LTGT_EXPR:
case RANGE_EXPR:
case COMPLEX_EXPR:
- r = cxx_eval_binary_expression (ctx, t, addr,
+ r = cxx_eval_binary_expression (ctx, t, lval,
non_constant_p, overflow_p);
break;
@@ -3233,7 +3233,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case TRUTH_ANDIF_EXPR:
r = cxx_eval_logical_expression (ctx, t, boolean_false_node,
boolean_true_node,
- addr,
+ lval,
non_constant_p, overflow_p);
break;
@@ -3241,12 +3241,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case TRUTH_ORIF_EXPR:
r = cxx_eval_logical_expression (ctx, t, boolean_true_node,
boolean_false_node,
- addr,
+ lval,
non_constant_p, overflow_p);
break;
case ARRAY_REF:
- r = cxx_eval_array_reference (ctx, t, addr,
+ r = cxx_eval_array_reference (ctx, t, lval,
non_constant_p, overflow_p);
break;
@@ -3261,24 +3261,24 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
- r = cxx_eval_component_reference (ctx, t, addr,
+ r = cxx_eval_component_reference (ctx, t, lval,
non_constant_p, overflow_p);
break;
case BIT_FIELD_REF:
- r = cxx_eval_bit_field_ref (ctx, t, addr,
+ r = cxx_eval_bit_field_ref (ctx, t, lval,
non_constant_p, overflow_p);
break;
case COND_EXPR:
case VEC_COND_EXPR:
- r = cxx_eval_conditional_expression (ctx, t, addr,
+ r = cxx_eval_conditional_expression (ctx, t, lval,
non_constant_p, overflow_p,
jump_target);
break;
case CONSTRUCTOR:
- r = cxx_eval_bare_aggregate (ctx, t, addr,
+ r = cxx_eval_bare_aggregate (ctx, t, lval,
non_constant_p, overflow_p);
break;
@@ -3288,13 +3288,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
be NULL, meaning default-initialization, or it will be an lvalue
or xvalue of the same type, meaning direct-initialization from the
corresponding member. */
- r = cxx_eval_vec_init (ctx, t, addr,
+ r = cxx_eval_vec_init (ctx, t, lval,
non_constant_p, overflow_p);
break;
case FMA_EXPR:
case VEC_PERM_EXPR:
- r = cxx_eval_trinary_expression (ctx, t, addr,
+ r = cxx_eval_trinary_expression (ctx, t, lval,
non_constant_p, overflow_p);
break;
@@ -3304,7 +3304,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
{
tree oldop = TREE_OPERAND (t, 0);
tree op = cxx_eval_constant_expression (ctx, oldop,
- addr,
+ lval,
non_constant_p, overflow_p);
if (*non_constant_p)
return t;
@@ -3344,7 +3344,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case BIND_EXPR:
return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t),
- addr,
+ lval,
non_constant_p, overflow_p,
jump_target);
@@ -3353,7 +3353,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
return cxx_eval_increment_expression (ctx, t,
- addr, non_constant_p, overflow_p);
+ lval, non_constant_p, overflow_p);
case LAMBDA_EXPR:
case NEW_EXPR:
@@ -3376,7 +3376,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
break;
case PLACEHOLDER_EXPR:
- if (!ctx || !ctx->ctor || (addr && !ctx->object))
+ if (!ctx || !ctx->ctor || (lval && !ctx->object))
{
/* A placeholder without a referent. We can get here when
checking whether NSDMIs are noexcept, or in massage_init_elt;
@@ -3390,11 +3390,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
/* Use of the value or address of the current object. We could
use ctx->object unconditionally, but using ctx->ctor when we
can is a minor optimization. */
- tree ctor = addr ? ctx->object : ctx->ctor;
+ tree ctor = lval ? ctx->object : ctx->ctor;
gcc_assert (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (t), TREE_TYPE (ctor)));
return cxx_eval_constant_expression
- (ctx, ctor, addr,
+ (ctx, ctor, lval,
non_constant_p, overflow_p);
}
break;
commit 58c6c2bb496d9ea2869ab6c88fbc0213b9cac729
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Dec 17 10:28:38 2014 -0500
* constexpr.c: Tweak comments and formatting.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 732a79c..1323111 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1,6 +1,5 @@
-/* Perform the semantic phase of constexpr parsing, i.e., the process of
- building tree structure, checking semantic consistency, and
- building RTL. These routines are used both during actual parsing
+/* Perform -*- C++ -*- constant expression evaluation, including calls to
+ constexpr functions. These routines are used both during actual parsing
and during the instantiation of template functions.
Copyright (C) 1998-2014 Free Software Foundation, Inc.
@@ -866,11 +865,20 @@ struct constexpr_call_hasher : ggc_hasher<constexpr_call *>
is a map of values of variables initialized within the expression. */
struct constexpr_ctx {
+ /* The innermost call we're evaluating. */
constexpr_call *call;
+ /* Values for any temporaries or local variables within the
+ constant-expression. */
hash_map<tree,tree> *values;
+ /* The CONSTRUCTOR we're currently building up for an aggregate
+ initializer. */
tree ctor;
+ /* The object we're building the CONSTRUCTOR for. */
tree object;
+ /* Whether we should error on a non-constant expression or fail quietly. */
bool quiet;
+ /* Whether we are strictly conforming to constant expression rules or
+ trying harder to get a constant value. */
bool strict;
};
@@ -3428,9 +3436,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
{
bool non_constant_p = false;
bool overflow_p = false;
- constexpr_ctx ctx = { NULL, NULL, NULL, NULL, allow_non_constant, strict };
hash_map<tree,tree> map;
- ctx.values = ↦
+ constexpr_ctx ctx = { NULL, &map, NULL, NULL, allow_non_constant, strict };
tree type = initialized_type (t);
tree r = t;
if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
@@ -3537,9 +3544,8 @@ is_sub_constant_expr (tree t)
{
bool non_constant_p = false;
bool overflow_p = false;
- constexpr_ctx ctx = { NULL, NULL, NULL, NULL, true, true };
hash_map <tree, tree> map;
- ctx.values = ↦
+ constexpr_ctx ctx = { NULL, &map, NULL, NULL, true, true };
cxx_eval_constant_expression (&ctx, t, false, &non_constant_p,
&overflow_p);
return !non_constant_p && !overflow_p;