c++: discarded-value and constexpr

I've been thinking for a while that the 'lval' parameter needed a third
value for discarded-value expressions; most importantly,
cxx_eval_store_expression does extra work for an lvalue result, and we also
don't want to do the l->r conversion.

Mostly this is pretty mechanical.  Apart from the _store_ fix, I also use
vc_discard for substatements of a STATEMENT_LIST other than a stmt-expr
result, and avoid building _REFs to be ignored in a few other places.

gcc/cp/ChangeLog:

	* constexpr.cc (enum value_cat): New. Change all 'lval' parameters
	from int to value_cat.  Change most false to vc_prvalue, most true
	to vc_glvalue, cases where the return value is ignored to
	vc_discard.
	(cxx_eval_statement_list): Only vc_prvalue for stmt-expr result.
	(cxx_eval_store_expression): Only build _REF for vc_glvalue.
	(cxx_eval_array_reference, cxx_eval_component_reference)
	(cxx_eval_indirect_ref, cxx_eval_constant_expression): Likewise.
This commit is contained in:
Jason Merrill 2022-05-19 12:24:33 -04:00
parent 2540e2c604
commit 72f76540ad
1 changed files with 108 additions and 90 deletions

View File

@ -1210,9 +1210,6 @@ uid_sensitive_constexpr_evaluation_checker::evaluation_restricted_p () const
static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table; static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table;
static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
bool, bool *, bool *, tree * = NULL);
/* Compute a hash value for a constexpr call representation. */ /* Compute a hash value for a constexpr call representation. */
inline hashval_t inline hashval_t
@ -1346,13 +1343,25 @@ get_nth_callarg (tree t, int n)
} }
} }
/* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST),
a glvalue (e.g. VAR_DECL or _REF), or nothing. */
enum value_cat {
vc_prvalue = 0,
vc_glvalue = 1,
vc_discard = 2
};
static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
value_cat, bool *, bool *, tree * = NULL);
/* Attempt to evaluate T which represents a call to a builtin function. /* Attempt to evaluate T which represents a call to a builtin function.
We assume here that all builtin functions evaluate to scalar types We assume here that all builtin functions evaluate to scalar types
represented by _CST nodes. */ represented by _CST nodes. */
static tree static tree
cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
const int nargs = call_expr_nargs (t); const int nargs = call_expr_nargs (t);
@ -1458,7 +1467,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
|| potential_constant_expression (arg)) || potential_constant_expression (arg))
{ {
bool dummy1 = false, dummy2 = false; bool dummy1 = false, dummy2 = false;
arg = cxx_eval_constant_expression (&new_ctx, arg, false, arg = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue,
&dummy1, &dummy2); &dummy1, &dummy2);
} }
@ -1703,7 +1712,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
/* Normally we would strip a TARGET_EXPR in an initialization context /* Normally we would strip a TARGET_EXPR in an initialization context
such as this, but here we do the elision differently: we keep the such as this, but here we do the elision differently: we keep the
TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */ TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */
arg = cxx_eval_constant_expression (ctx, x, /*lval=*/false, arg = cxx_eval_constant_expression (ctx, x, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT here. */ /* Don't VERIFY_CONSTANT here. */
if (*non_constant_p && ctx->quiet) if (*non_constant_p && ctx->quiet)
@ -1807,7 +1816,7 @@ cx_error_context (void)
static tree static tree
cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
enum tree_code opcode = ERROR_MARK; enum tree_code opcode = ERROR_MARK;
@ -1832,12 +1841,13 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
case IFN_LAUNDER: case IFN_LAUNDER:
return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
false, non_constant_p, overflow_p); vc_prvalue, non_constant_p,
overflow_p);
case IFN_VEC_CONVERT: case IFN_VEC_CONVERT:
{ {
tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
false, non_constant_p, vc_prvalue, non_constant_p,
overflow_p); overflow_p);
if (TREE_CODE (arg) == VECTOR_CST) if (TREE_CODE (arg) == VECTOR_CST)
if (tree r = fold_const_call (CFN_VEC_CONVERT, TREE_TYPE (t), arg)) if (tree r = fold_const_call (CFN_VEC_CONVERT, TREE_TYPE (t), arg))
@ -2103,7 +2113,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
} }
/* Evaluate the object so that we know its dynamic type. */ /* Evaluate the object so that we know its dynamic type. */
obj = cxx_eval_constant_expression (ctx, obj, /*lval*/false, non_constant_p, obj = cxx_eval_constant_expression (ctx, obj, vc_prvalue, non_constant_p,
overflow_p); overflow_p);
if (*non_constant_p) if (*non_constant_p)
return call; return call;
@ -2138,7 +2148,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
considered to be a most derived object that has the type of the considered to be a most derived object that has the type of the
constructor or destructor's class. */ constructor or destructor's class. */
tree vtable = build_vfield_ref (obj, objtype); tree vtable = build_vfield_ref (obj, objtype);
vtable = cxx_eval_constant_expression (ctx, vtable, /*lval*/false, vtable = cxx_eval_constant_expression (ctx, vtable, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (*non_constant_p) if (*non_constant_p)
return call; return call;
@ -2301,7 +2311,7 @@ replace_decl (tree *tp, tree decl, tree replacement)
static tree static tree
cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl, cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
tree function = THUNK_TARGET (thunk_fndecl); tree function = THUNK_TARGET (thunk_fndecl);
@ -2362,7 +2372,7 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object,
{ {
/* Subobjects might not be stored in ctx->global->values but we /* Subobjects might not be stored in ctx->global->values but we
can get its CONSTRUCTOR by evaluating *this. */ can get its CONSTRUCTOR by evaluating *this. */
tree e = cxx_eval_constant_expression (ctx, object, /*lval*/false, tree e = cxx_eval_constant_expression (ctx, object, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (TREE_CODE (e) == CONSTRUCTOR && !*non_constant_p) if (TREE_CODE (e) == CONSTRUCTOR && !*non_constant_p)
TREE_READONLY (e) = readonly_p; TREE_READONLY (e) = readonly_p;
@ -2375,7 +2385,7 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object,
static tree static tree
cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
/* Handle concept checks separately. */ /* Handle concept checks separately. */
@ -2395,9 +2405,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (fun) != FUNCTION_DECL) if (TREE_CODE (fun) != FUNCTION_DECL)
{ {
/* Might be a constexpr function pointer. */ /* Might be a constexpr function pointer. */
fun = cxx_eval_constant_expression (ctx, fun, fun = cxx_eval_constant_expression (ctx, fun, vc_prvalue,
/*lval*/false, non_constant_p, non_constant_p, overflow_p);
overflow_p);
STRIP_NOPS (fun); STRIP_NOPS (fun);
if (TREE_CODE (fun) == ADDR_EXPR) if (TREE_CODE (fun) == ADDR_EXPR)
fun = TREE_OPERAND (fun, 0); fun = TREE_OPERAND (fun, 0);
@ -2463,7 +2472,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
for (int i = 0; i < nargs; ++i) for (int i = 0; i < nargs; ++i)
{ {
tree arg = CALL_EXPR_ARG (t, i); tree arg = CALL_EXPR_ARG (t, i);
arg = cxx_eval_constant_expression (ctx, arg, false, arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (arg); VERIFY_CONSTANT (arg);
if (i == 0) if (i == 0)
@ -2571,7 +2580,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
for (int i = 0; i < nargs; ++i) for (int i = 0; i < nargs; ++i)
{ {
tree arg = CALL_EXPR_ARG (t, i); tree arg = CALL_EXPR_ARG (t, i);
arg = cxx_eval_constant_expression (ctx, arg, false, arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (i == 1) if (i == 1)
arg1 = arg; arg1 = arg;
@ -2852,7 +2861,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
tree jump_target = NULL_TREE; tree jump_target = NULL_TREE;
cxx_eval_constant_expression (&ctx_with_save_exprs, body, cxx_eval_constant_expression (&ctx_with_save_exprs, body,
lval, non_constant_p, overflow_p, vc_discard, non_constant_p, overflow_p,
&jump_target); &jump_target);
if (DECL_CONSTRUCTOR_P (fun)) if (DECL_CONSTRUCTOR_P (fun))
@ -3213,7 +3222,7 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
{ {
tree r; tree r;
tree orig_arg = TREE_OPERAND (t, 0); tree orig_arg = TREE_OPERAND (t, 0);
tree arg = cxx_eval_constant_expression (ctx, orig_arg, /*lval*/false, tree arg = cxx_eval_constant_expression (ctx, orig_arg, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (arg); VERIFY_CONSTANT (arg);
location_t loc = EXPR_LOCATION (t); location_t loc = EXPR_LOCATION (t);
@ -3259,8 +3268,8 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1)); t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1));
tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0))); tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0)));
nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p, nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue,
overflow_p); non_constant_p, overflow_p);
if (*non_constant_p) if (*non_constant_p)
return NULL_TREE; return NULL_TREE;
/* Don't fold an out-of-bound access. */ /* Don't fold an out-of-bound access. */
@ -3281,7 +3290,7 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
t, NULL_TREE, NULL_TREE); t, NULL_TREE, NULL_TREE);
t = cp_build_addr_expr (t, tf_warning_or_error); t = cp_build_addr_expr (t, tf_warning_or_error);
t = cp_fold_convert (orig_type, t); t = cp_fold_convert (orig_type, t);
return cxx_eval_constant_expression (ctx, t, /*lval*/false, return cxx_eval_constant_expression (ctx, t, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
} }
@ -3325,20 +3334,20 @@ cxx_maybe_fold_addr_pointer_plus (tree t)
static tree static tree
cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
tree r = NULL_TREE; tree r = NULL_TREE;
tree orig_lhs = TREE_OPERAND (t, 0); tree orig_lhs = TREE_OPERAND (t, 0);
tree orig_rhs = TREE_OPERAND (t, 1); tree orig_rhs = TREE_OPERAND (t, 1);
tree lhs, rhs; tree lhs, rhs;
lhs = cxx_eval_constant_expression (ctx, orig_lhs, /*lval*/false, lhs = cxx_eval_constant_expression (ctx, orig_lhs, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer /* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer
subtraction. */ subtraction. */
if (*non_constant_p) if (*non_constant_p)
return t; return t;
rhs = cxx_eval_constant_expression (ctx, orig_rhs, /*lval*/false, rhs = cxx_eval_constant_expression (ctx, orig_rhs, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (*non_constant_p) if (*non_constant_p)
return t; return t;
@ -3457,12 +3466,12 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
static tree static tree
cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p, bool *non_constant_p, bool *overflow_p,
tree *jump_target) tree *jump_target)
{ {
tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
/*lval*/false, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (val); VERIFY_CONSTANT (val);
if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t)) if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t))
@ -3504,15 +3513,15 @@ cxx_eval_vector_conditional_expression (const constexpr_ctx *ctx, tree t,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
tree arg1 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), tree arg1 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
/*lval*/false, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (arg1); VERIFY_CONSTANT (arg1);
tree arg2 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), tree arg2 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
/*lval*/false, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (arg2); VERIFY_CONSTANT (arg2);
tree arg3 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2), tree arg3 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
/*lval*/false, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (arg3); VERIFY_CONSTANT (arg3);
location_t loc = EXPR_LOCATION (t); location_t loc = EXPR_LOCATION (t);
@ -3844,7 +3853,7 @@ get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
gcc_unreachable (); gcc_unreachable ();
/* For VLAs, the number of elements won't be an integer constant. */ /* For VLAs, the number of elements won't be an integer constant. */
nelts = cxx_eval_constant_expression (ctx, nelts, false, nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
return nelts; return nelts;
} }
@ -3881,7 +3890,7 @@ eval_and_check_array_index (const constexpr_ctx *ctx,
location_t loc = cp_expr_loc_or_input_loc (t); location_t loc = cp_expr_loc_or_input_loc (t);
tree ary = TREE_OPERAND (t, 0); tree ary = TREE_OPERAND (t, 0);
t = TREE_OPERAND (t, 1); t = TREE_OPERAND (t, 1);
tree index = cxx_eval_constant_expression (ctx, t, false, tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (index); VERIFY_CONSTANT (index);
@ -3913,7 +3922,7 @@ eval_and_check_array_index (const constexpr_ctx *ctx,
static tree static tree
cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
tree oldary = TREE_OPERAND (t, 0); tree oldary = TREE_OPERAND (t, 0);
@ -3936,6 +3945,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
if (lval && ary == oldary && index == oldidx) if (lval && ary == oldary && index == oldidx)
return t; return t;
else if (lval == vc_discard)
return t;
else if (lval) else if (lval)
return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL); return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
@ -4043,7 +4054,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
static tree static tree
cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
unsigned HOST_WIDE_INT i; unsigned HOST_WIDE_INT i;
@ -4067,6 +4078,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
whole = cplus_expand_constant (whole); whole = cplus_expand_constant (whole);
if (whole == orig_whole) if (whole == orig_whole)
return t; return t;
if (lval == vc_discard)
return t;
if (lval) if (lval)
return fold_build3 (COMPONENT_REF, TREE_TYPE (t), return fold_build3 (COMPONENT_REF, TREE_TYPE (t),
whole, part, NULL_TREE); whole, part, NULL_TREE);
@ -4152,7 +4165,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
static tree static tree
cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
tree orig_whole = TREE_OPERAND (t, 0); tree orig_whole = TREE_OPERAND (t, 0);
@ -4449,7 +4462,7 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
return t; return t;
} }
tree op = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false, tree op = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (*non_constant_p) if (*non_constant_p)
return t; return t;
@ -4569,14 +4582,14 @@ cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t,
{ {
tree r; tree r;
tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
/*lval*/false, non_constant_p, vc_prvalue, non_constant_p,
overflow_p); overflow_p);
VERIFY_CONSTANT (lhs); VERIFY_CONSTANT (lhs);
if (tree_int_cst_equal (lhs, bailout_value)) if (tree_int_cst_equal (lhs, bailout_value))
return lhs; return lhs;
gcc_assert (tree_int_cst_equal (lhs, continue_value)); gcc_assert (tree_int_cst_equal (lhs, continue_value));
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
/*lval*/false, non_constant_p, vc_prvalue, non_constant_p,
overflow_p); overflow_p);
VERIFY_CONSTANT (r); VERIFY_CONSTANT (r);
return r; return r;
@ -4725,7 +4738,7 @@ verify_ctor_sanity (const constexpr_ctx *ctx, tree type)
static tree static tree
cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t); vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t);
@ -4858,7 +4871,7 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
static tree static tree
cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
bool value_init, bool lval, bool value_init, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
tree elttype = TREE_TYPE (atype); tree elttype = TREE_TYPE (atype);
@ -5000,7 +5013,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
static tree static tree
cxx_eval_vec_init (const constexpr_ctx *ctx, tree t, cxx_eval_vec_init (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
tree atype = TREE_TYPE (t); tree atype = TREE_TYPE (t);
@ -5070,7 +5083,7 @@ cxx_union_active_member (const constexpr_ctx *ctx, tree t)
constexpr_ctx new_ctx = *ctx; constexpr_ctx new_ctx = *ctx;
new_ctx.quiet = true; new_ctx.quiet = true;
bool non_constant_p = false, overflow_p = false; bool non_constant_p = false, overflow_p = false;
tree ctor = cxx_eval_constant_expression (&new_ctx, t, false, tree ctor = cxx_eval_constant_expression (&new_ctx, t, vc_prvalue,
&non_constant_p, &non_constant_p,
&overflow_p); &overflow_p);
if (TREE_CODE (ctor) == CONSTRUCTOR if (TREE_CODE (ctor) == CONSTRUCTOR
@ -5306,7 +5319,7 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
static tree static tree
cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
tree orig_op0 = TREE_OPERAND (t, 0); tree orig_op0 = TREE_OPERAND (t, 0);
@ -5330,7 +5343,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
{ {
/* If that didn't work, evaluate the operand first. */ /* If that didn't work, evaluate the operand first. */
tree op0 = cxx_eval_constant_expression (ctx, orig_op0, tree op0 = cxx_eval_constant_expression (ctx, orig_op0,
/*lval*/false, non_constant_p, vc_prvalue, non_constant_p,
overflow_p); overflow_p);
/* Don't VERIFY_CONSTANT here. */ /* Don't VERIFY_CONSTANT here. */
if (*non_constant_p) if (*non_constant_p)
@ -5366,7 +5379,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
return t; return t;
} }
if (lval && op0 != orig_op0) if (lval == vc_glvalue && op0 != orig_op0)
return build1 (INDIRECT_REF, TREE_TYPE (t), op0); return build1 (INDIRECT_REF, TREE_TYPE (t), op0);
if (!lval) if (!lval)
VERIFY_CONSTANT (t); VERIFY_CONSTANT (t);
@ -5462,7 +5475,7 @@ non_const_var_error (location_t loc, tree r)
static tree static tree
cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
int i; int i;
@ -5594,7 +5607,7 @@ modifying_const_object_p (tree_code code, tree obj, bool mutable_p)
static tree static tree
cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
constexpr_ctx new_ctx = *ctx; constexpr_ctx new_ctx = *ctx;
@ -5617,19 +5630,19 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
stored in, so that any side-effects happen first. */ stored in, so that any side-effects happen first. */
if (!SCALAR_TYPE_P (type)) if (!SCALAR_TYPE_P (type))
new_ctx.ctor = new_ctx.object = NULL_TREE; new_ctx.ctor = new_ctx.object = NULL_TREE;
init = cxx_eval_constant_expression (&new_ctx, init, false, init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (*non_constant_p) if (*non_constant_p)
return t; return t;
} }
bool evaluated = false; bool evaluated = false;
if (lval) if (lval == vc_glvalue)
{ {
/* If we want to return a reference to the target, we need to evaluate it /* If we want to return a reference to the target, we need to evaluate it
as a whole; otherwise, only evaluate the innermost piece to avoid as a whole; otherwise, only evaluate the innermost piece to avoid
building up unnecessary *_REFs. */ building up unnecessary *_REFs. */
target = cxx_eval_constant_expression (ctx, target, true, target = cxx_eval_constant_expression (ctx, target, lval,
non_constant_p, overflow_p); non_constant_p, overflow_p);
evaluated = true; evaluated = true;
if (*non_constant_p) if (*non_constant_p)
@ -5681,7 +5694,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
object = probe; object = probe;
else else
{ {
probe = cxx_eval_constant_expression (ctx, probe, true, probe = cxx_eval_constant_expression (ctx, probe, vc_glvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
evaluated = true; evaluated = true;
if (*non_constant_p) if (*non_constant_p)
@ -5893,7 +5906,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (init) == TARGET_EXPR) if (TREE_CODE (init) == TARGET_EXPR)
if (tree tinit = TARGET_EXPR_INITIAL (init)) if (tree tinit = TARGET_EXPR_INITIAL (init))
init = tinit; init = tinit;
init = cxx_eval_constant_expression (&new_ctx, init, false, init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
/* The hash table might have moved since the get earlier, and the /* The hash table might have moved since the get earlier, and the
initializer might have mutated the underlying CONSTRUCTORs, so we must initializer might have mutated the underlying CONSTRUCTORs, so we must
@ -5992,7 +6005,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
static tree static tree
cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p) bool *non_constant_p, bool *overflow_p)
{ {
enum tree_code code = TREE_CODE (t); enum tree_code code = TREE_CODE (t);
@ -6006,12 +6019,12 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
offset = fold_simple (offset); offset = fold_simple (offset);
/* The operand as an lvalue. */ /* The operand as an lvalue. */
op = cxx_eval_constant_expression (ctx, op, true, op = cxx_eval_constant_expression (ctx, op, vc_glvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
/* The operand as an rvalue. */ /* The operand as an rvalue. */
tree val tree val
= cxx_eval_constant_expression (ctx, op, false, = cxx_eval_constant_expression (ctx, op, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT if this might be dealing with a pointer to /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
a local array in a constexpr function. */ a local array in a constexpr function. */
@ -6160,8 +6173,10 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
local_target = NULL_TREE; local_target = NULL_TREE;
jump_target = &local_target; jump_target = &local_target;
} }
for (tree stmt : tsi_range (t)) for (tree_stmt_iterator i = tsi_start (t); !tsi_end_p (i); ++i)
{ {
tree stmt = *i;
/* We've found a continue, so skip everything until we reach /* We've found a continue, so skip everything until we reach
the label its jumping to. */ the label its jumping to. */
if (continues (jump_target)) if (continues (jump_target))
@ -6174,7 +6189,13 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
} }
if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT) if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
continue; continue;
r = cxx_eval_constant_expression (ctx, stmt, false,
value_cat lval = vc_discard;
/* The result of a statement-expression is not wrapped in EXPR_STMT. */
if (tsi_one_before_end_p (i) && TREE_CODE (stmt) != EXPR_STMT)
lval = vc_prvalue;
r = cxx_eval_constant_expression (ctx, stmt, lval,
non_constant_p, overflow_p, non_constant_p, overflow_p,
jump_target); jump_target);
if (*non_constant_p) if (*non_constant_p)
@ -6228,7 +6249,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
break; break;
case FOR_STMT: case FOR_STMT:
if (FOR_INIT_STMT (t)) if (FOR_INIT_STMT (t))
cxx_eval_constant_expression (ctx, FOR_INIT_STMT (t), /*lval*/false, cxx_eval_constant_expression (ctx, FOR_INIT_STMT (t), vc_discard,
non_constant_p, overflow_p, jump_target); non_constant_p, overflow_p, jump_target);
if (*non_constant_p) if (*non_constant_p)
return NULL_TREE; return NULL_TREE;
@ -6247,7 +6268,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
if (count != -1) if (count != -1)
{ {
if (body) if (body)
cxx_eval_constant_expression (&new_ctx, body, /*lval*/false, cxx_eval_constant_expression (&new_ctx, body, vc_discard,
non_constant_p, overflow_p, non_constant_p, overflow_p,
jump_target); jump_target);
if (breaks (jump_target)) if (breaks (jump_target))
@ -6260,7 +6281,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
*jump_target = NULL_TREE; *jump_target = NULL_TREE;
if (expr) if (expr)
cxx_eval_constant_expression (&new_ctx, expr, /*lval*/false, cxx_eval_constant_expression (&new_ctx, expr, vc_prvalue,
non_constant_p, overflow_p, non_constant_p, overflow_p,
jump_target); jump_target);
} }
@ -6268,7 +6289,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
if (cond) if (cond)
{ {
tree res tree res
= cxx_eval_constant_expression (&new_ctx, cond, /*lval*/false, = cxx_eval_constant_expression (&new_ctx, cond, vc_prvalue,
non_constant_p, overflow_p, non_constant_p, overflow_p,
jump_target); jump_target);
if (res) if (res)
@ -6322,7 +6343,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
{ {
tree cond tree cond
= TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_COND (t) : SWITCH_COND (t); = TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_COND (t) : SWITCH_COND (t);
cond = cxx_eval_constant_expression (ctx, cond, false, cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (cond); VERIFY_CONSTANT (cond);
*jump_target = cond; *jump_target = cond;
@ -6332,7 +6353,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
constexpr_ctx new_ctx = *ctx; constexpr_ctx new_ctx = *ctx;
constexpr_switch_state css = css_default_not_seen; constexpr_switch_state css = css_default_not_seen;
new_ctx.css_state = &css; new_ctx.css_state = &css;
cxx_eval_constant_expression (&new_ctx, body, false, cxx_eval_constant_expression (&new_ctx, body, vc_discard,
non_constant_p, overflow_p, jump_target); non_constant_p, overflow_p, jump_target);
if (switches (jump_target) && css == css_default_seen) if (switches (jump_target) && css == css_default_seen)
{ {
@ -6340,7 +6361,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
this time instructing label_matches to return true for default: this time instructing label_matches to return true for default:
label on switches (jump_target). */ label on switches (jump_target). */
css = css_default_processing; css = css_default_processing;
cxx_eval_constant_expression (&new_ctx, body, false, cxx_eval_constant_expression (&new_ctx, body, vc_discard,
non_constant_p, overflow_p, jump_target); non_constant_p, overflow_p, jump_target);
} }
if (breaks (jump_target) || switches (jump_target)) if (breaks (jump_target) || switches (jump_target))
@ -6351,7 +6372,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
/* Find the object of TYPE under initialization in CTX. */ /* Find the object of TYPE under initialization in CTX. */
static tree static tree
lookup_placeholder (const constexpr_ctx *ctx, bool lval, tree type) lookup_placeholder (const constexpr_ctx *ctx, value_cat lval, tree type)
{ {
if (!ctx) if (!ctx)
return NULL_TREE; return NULL_TREE;
@ -6478,12 +6499,12 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type,
tree op1 = TREE_OPERAND (arg_size, 1); tree op1 = TREE_OPERAND (arg_size, 1);
if (integer_zerop (op0)) if (integer_zerop (op0))
arg_size arg_size
= cxx_eval_constant_expression (ctx, op1, false, non_constant_p, = cxx_eval_constant_expression (ctx, op1, vc_prvalue,
overflow_p); non_constant_p, overflow_p);
else if (integer_zerop (op1)) else if (integer_zerop (op1))
arg_size arg_size
= cxx_eval_constant_expression (ctx, op0, false, non_constant_p, = cxx_eval_constant_expression (ctx, op0, vc_prvalue,
overflow_p); non_constant_p, overflow_p);
else else
arg_size = NULL_TREE; arg_size = NULL_TREE;
} }
@ -6513,7 +6534,7 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type,
static tree static tree
cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
bool lval, value_cat lval,
bool *non_constant_p, bool *overflow_p, bool *non_constant_p, bool *overflow_p,
tree *jump_target /* = NULL */) tree *jump_target /* = NULL */)
{ {
@ -6760,8 +6781,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (tree init = DECL_INITIAL (r)) if (tree init = DECL_INITIAL (r))
{ {
init = cxx_eval_constant_expression (ctx, init, init = cxx_eval_constant_expression (ctx, init, vc_prvalue,
false,
non_constant_p, overflow_p); non_constant_p, overflow_p);
/* Don't share a CONSTRUCTOR that might be changed. */ /* Don't share a CONSTRUCTOR that might be changed. */
init = unshare_constructor (init); init = unshare_constructor (init);
@ -6821,10 +6841,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
ctx->global->values.put (new_ctx.object, new_ctx.ctor); ctx->global->values.put (new_ctx.object, new_ctx.ctor);
ctx = &new_ctx; ctx = &new_ctx;
} }
/* Pass false for 'lval' because this indicates /* Pass vc_prvalue because this indicates
initialization of a temporary. */ initialization of a temporary. */
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue,
false,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (*non_constant_p) if (*non_constant_p)
break; break;
@ -6880,7 +6899,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = *p; r = *p;
else else
{ {
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false, r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (*non_constant_p) if (*non_constant_p)
break; break;
@ -6922,7 +6941,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
tree cleanup; tree cleanup;
/* Evaluate the cleanups. */ /* Evaluate the cleanups. */
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
cxx_eval_constant_expression (ctx, cleanup, false, cxx_eval_constant_expression (ctx, cleanup, vc_discard,
non_constant_p, overflow_p); non_constant_p, overflow_p);
} }
break; break;
@ -6933,7 +6952,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
jump_target); jump_target);
if (!*non_constant_p) if (!*non_constant_p)
/* Also evaluate the cleanup. */ /* Also evaluate the cleanup. */
cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), true, cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard,
non_constant_p, overflow_p); non_constant_p, overflow_p);
break; break;
@ -6945,7 +6964,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
{ {
iloc_sentinel ils (loc); iloc_sentinel ils (loc);
/* Also evaluate the cleanup. */ /* Also evaluate the cleanup. */
cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), vc_discard,
non_constant_p, overflow_p); non_constant_p, overflow_p);
} }
break; break;
@ -6962,8 +6981,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case ADDR_EXPR: case ADDR_EXPR:
{ {
tree oldop = TREE_OPERAND (t, 0); tree oldop = TREE_OPERAND (t, 0);
tree op = cxx_eval_constant_expression (ctx, oldop, tree op = cxx_eval_constant_expression (ctx, oldop, vc_glvalue,
/*lval*/true,
non_constant_p, overflow_p); non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT here. */ /* Don't VERIFY_CONSTANT here. */
if (*non_constant_p) if (*non_constant_p)
@ -6987,7 +7005,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
non_constant_p, overflow_p); non_constant_p, overflow_p);
if (r == error_mark_node) if (r == error_mark_node)
; ;
else if (r == TREE_OPERAND (t, 0)) else if (r == TREE_OPERAND (t, 0) || lval == vc_discard)
r = t; r = t;
else else
r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), r); r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), r);
@ -7039,8 +7057,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
else else
{ {
/* Check that the LHS is constant and then discard it. */ /* Check that the LHS is constant and then discard it. */
cxx_eval_constant_expression (ctx, op0, cxx_eval_constant_expression (ctx, op0, vc_discard,
true, non_constant_p, overflow_p, non_constant_p, overflow_p,
jump_target); jump_target);
if (*non_constant_p) if (*non_constant_p)
return t; return t;
@ -7461,7 +7479,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case EXIT_EXPR: case EXIT_EXPR:
{ {
tree cond = TREE_OPERAND (t, 0); tree cond = TREE_OPERAND (t, 0);
cond = cxx_eval_constant_expression (ctx, cond, /*lval*/false, cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (cond); VERIFY_CONSTANT (cond);
if (integer_nonzerop (cond)) if (integer_nonzerop (cond))
@ -7820,8 +7838,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (manifestly_const_eval) if (manifestly_const_eval)
instantiate_constexpr_fns (r); instantiate_constexpr_fns (r);
r = cxx_eval_constant_expression (&ctx, r, r = cxx_eval_constant_expression (&ctx, r, vc_prvalue,
false, &non_constant_p, &overflow_p); &non_constant_p, &overflow_p);
if (!constexpr_dtor) if (!constexpr_dtor)
verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
@ -7832,7 +7850,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
tree cleanup; tree cleanup;
/* Evaluate the cleanups. */ /* Evaluate the cleanups. */
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
cxx_eval_constant_expression (&ctx, cleanup, false, cxx_eval_constant_expression (&ctx, cleanup, vc_discard,
&non_constant_p, &overflow_p); &non_constant_p, &overflow_p);
/* Mutable logic is a bit tricky: we want to allow initialization of /* Mutable logic is a bit tricky: we want to allow initialization of