aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/constexpr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r--gcc/cp/constexpr.c357
1 files changed, 267 insertions, 90 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index c946744..0c2498a 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -46,6 +46,7 @@ do { \
static HOST_WIDE_INT find_array_ctor_elt (tree ary, tree dindex,
bool insert = false);
+static int array_index_cmp (tree key, tree index);
/* Returns true iff FUN is an instantiation of a constexpr function
template or a defaulted constexpr function. */
@@ -329,12 +330,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
return false;
if (TREE_CODE (t) == STATEMENT_LIST)
{
- tree_stmt_iterator i;
- for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
- {
- if (! build_data_member_initialization (tsi_stmt (i), vec))
- return false;
- }
+ for (tree stmt : tsi_range (t))
+ if (! build_data_member_initialization (stmt, vec))
+ return false;
return true;
}
if (TREE_CODE (t) == CLEANUP_STMT)
@@ -576,10 +574,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
break;
case STATEMENT_LIST:
- for (tree_stmt_iterator i = tsi_start (body);
- !tsi_end_p (i); tsi_next (&i))
+ for (tree stmt : tsi_range (body))
{
- body = tsi_stmt (i);
+ body = stmt;
if (TREE_CODE (body) == BIND_EXPR)
break;
}
@@ -616,10 +613,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
}
else if (TREE_CODE (body) == STATEMENT_LIST)
{
- tree_stmt_iterator i;
- for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
+ for (tree stmt : tsi_range (body))
{
- ok = build_data_member_initialization (tsi_stmt (i), &vec);
+ ok = build_data_member_initialization (stmt, &vec);
if (!ok)
break;
}
@@ -674,11 +670,10 @@ constexpr_fn_retval (tree body)
{
case STATEMENT_LIST:
{
- tree_stmt_iterator i;
tree expr = NULL_TREE;
- for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
+ for (tree stmt : tsi_range (body))
{
- tree s = constexpr_fn_retval (tsi_stmt (i));
+ tree s = constexpr_fn_retval (stmt);
if (s == error_mark_node)
return error_mark_node;
else if (s == NULL_TREE)
@@ -870,7 +865,7 @@ maybe_save_constexpr_fundef (tree fun)
if (processing_template_decl
|| !DECL_DECLARED_CONSTEXPR_P (fun)
|| cp_function_chain->invalid_constexpr
- || DECL_CLONED_FUNCTION_P (fun))
+ || (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun)))
return;
if (!is_valid_constexpr_fn (fun, !DECL_GENERATED_P (fun)))
@@ -947,7 +942,6 @@ explain_invalid_constexpr_fn (tree fun)
{
static hash_set<tree> *diagnosed;
tree body;
- location_t save_loc;
/* Only diagnose defaulted functions, lambdas, or instantiations. */
if (!DECL_DEFAULTED_FN (fun)
&& !LAMBDA_TYPE_P (CP_DECL_CONTEXT (fun))
@@ -962,7 +956,7 @@ explain_invalid_constexpr_fn (tree fun)
/* Already explained. */
return;
- save_loc = input_location;
+ iloc_sentinel ils = input_location;
if (!lambda_static_thunk_p (fun))
{
/* Diagnostics should completely ignore the static thunk, so leave
@@ -990,7 +984,6 @@ explain_invalid_constexpr_fn (tree fun)
cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true);
}
}
- input_location = save_loc;
}
/* Objects of this type represent calls to constexpr functions
@@ -1320,7 +1313,10 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
}
/* For __builtin_is_constant_evaluated, defer it if not
- ctx->manifestly_const_eval, otherwise fold it to true. */
+ ctx->manifestly_const_eval (as sometimes we try to constant evaluate
+ without manifestly_const_eval even expressions or parts thereof which
+ will later be manifestly const_eval evaluated), otherwise fold it to
+ true. */
if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
BUILT_IN_FRONTEND))
{
@@ -1429,8 +1425,32 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
&& ctx->call
&& ctx->call->fundef)
current_function_decl = ctx->call->fundef->decl;
- new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
- CALL_EXPR_FN (t), nargs, args);
+ if (fndecl_built_in_p (fun,
+ CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS,
+ BUILT_IN_FRONTEND))
+ {
+ location_t loc = EXPR_LOCATION (t);
+ if (nargs >= 1)
+ VERIFY_CONSTANT (args[0]);
+ new_call
+ = fold_builtin_is_pointer_inverconvertible_with_class (loc, nargs,
+ args);
+ }
+ else if (fndecl_built_in_p (fun,
+ CP_BUILT_IN_IS_CORRESPONDING_MEMBER,
+ BUILT_IN_FRONTEND))
+ {
+ location_t loc = EXPR_LOCATION (t);
+ if (nargs >= 2)
+ {
+ VERIFY_CONSTANT (args[0]);
+ VERIFY_CONSTANT (args[1]);
+ }
+ new_call = fold_builtin_is_corresponding_member (loc, nargs, args);
+ }
+ else
+ new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
+ CALL_EXPR_FN (t), nargs, args);
current_function_decl = save_cur_fn;
force_folding_builtin_constant_p = save_ffbcp;
if (new_call == NULL)
@@ -1555,6 +1575,32 @@ free_constructor (tree t)
}
}
+/* Helper function of cxx_bind_parameters_in_call. Return non-NULL
+ if *TP is address of a static variable (or part of it) currently being
+ constructed or of a heap artificial variable. */
+
+static tree
+addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data)
+{
+ if (TREE_CODE (*tp) == ADDR_EXPR)
+ if (tree var = get_base_address (TREE_OPERAND (*tp, 0)))
+ if (VAR_P (var) && TREE_STATIC (var))
+ {
+ if (DECL_NAME (var) == heap_uninit_identifier
+ || DECL_NAME (var) == heap_identifier
+ || DECL_NAME (var) == heap_vec_uninit_identifier
+ || DECL_NAME (var) == heap_vec_identifier)
+ return var;
+
+ constexpr_global_ctx *global = (constexpr_global_ctx *) data;
+ if (global->values.get (var))
+ return var;
+ }
+ if (TYPE_P (*tp))
+ *walk_subtrees = false;
+ return NULL_TREE;
+}
+
/* Subroutine of cxx_eval_call_expression.
We are processing a call expression (either CALL_EXPR or
AGGR_INIT_EXPR) in the context of CTX. Evaluate
@@ -1616,6 +1662,15 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
/* The destructor needs to see any modifications the callee makes
to the argument. */
*non_constant_args = true;
+ /* If arg is or contains address of a heap artificial variable or
+ of a static variable being constructed, avoid caching the
+ function call, as those variables might be modified by the
+ function, or might be modified by the callers in between
+ the cached function and just read by the function. */
+ else if (!*non_constant_args
+ && cp_walk_tree (&arg, addr_of_non_const_var, ctx->global,
+ NULL))
+ *non_constant_args = true;
/* For virtual calls, adjust the this argument, so that it is
the object on which the method is called, rather than
@@ -2317,7 +2372,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
- if (DECL_CLONED_FUNCTION_P (fun))
+ if (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun))
fun = DECL_CLONED_FUNCTION (fun);
if (is_ubsan_builtin_p (fun))
@@ -2515,6 +2570,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
location_t save_loc = input_location;
input_location = loc;
++function_depth;
+ if (ctx->manifestly_const_eval)
+ FNDECL_MANIFESTLY_CONST_EVALUATED (fun) = true;
instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false);
--function_depth;
input_location = save_loc;
@@ -2760,9 +2817,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
/* Forget the saved values of the callee's SAVE_EXPRs and
TARGET_EXPRs. */
- unsigned int i;
- tree save_expr;
- FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
+ for (tree save_expr : save_exprs)
ctx->global->values.remove (save_expr);
/* Remove the parms/result from the values map. Is it worth
@@ -2875,9 +2930,27 @@ reduced_constant_expression_p (tree t)
/* An initialized vector would have a VECTOR_CST. */
return false;
else if (cxx_dialect >= cxx20
- /* An ARRAY_TYPE doesn't have any TYPE_FIELDS. */
&& TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
- field = NULL_TREE;
+ {
+ /* There must be a valid constant initializer at every array
+ index. */
+ tree min = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
+ tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
+ tree cursor = min;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), i, idx, val)
+ {
+ if (!reduced_constant_expression_p (val))
+ return false;
+ if (array_index_cmp (cursor, idx) != 0)
+ return false;
+ if (TREE_CODE (idx) == RANGE_EXPR)
+ cursor = TREE_OPERAND (idx, 1);
+ cursor = int_const_binop (PLUS_EXPR, cursor, size_one_node);
+ }
+ if (find_array_ctor_elt (t, max) == -1)
+ return false;
+ goto ok;
+ }
else if (cxx_dialect >= cxx20
&& TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
{
@@ -2911,6 +2984,7 @@ reduced_constant_expression_p (tree t)
for (; field; field = next_initializable_field (DECL_CHAIN (field)))
if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false))
return false;
+ok:
if (CONSTRUCTOR_NO_CLEARING (t))
/* All the fields are initialized. */
CONSTRUCTOR_NO_CLEARING (t) = false;
@@ -3249,6 +3323,22 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
/*lval*/false,
non_constant_p, overflow_p);
VERIFY_CONSTANT (val);
+ if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t))
+ {
+ /* Evaluate the condition as if it was
+ if (__builtin_is_constant_evaluated ()), i.e. defer it if not
+ ctx->manifestly_const_eval (as sometimes we try to constant evaluate
+ without manifestly_const_eval even expressions or parts thereof which
+ will later be manifestly const_eval evaluated), otherwise fold it to
+ true. */
+ if (ctx->manifestly_const_eval)
+ val = boolean_true_node;
+ else
+ {
+ *non_constant_p = true;
+ return t;
+ }
+ }
/* Don't VERIFY_CONSTANT the other operands. */
if (integer_zerop (val))
val = TREE_OPERAND (t, 2);
@@ -3779,20 +3869,29 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
directly for non-aggregates to avoid creating a garbage CONSTRUCTOR. */
tree val;
constexpr_ctx new_ctx;
- if (CP_AGGREGATE_TYPE_P (elem_type))
+ if (is_really_empty_class (elem_type, /*ignore_vptr*/false))
+ return build_constructor (elem_type, NULL);
+ else if (CP_AGGREGATE_TYPE_P (elem_type))
{
tree empty_ctor = build_constructor (init_list_type_node, NULL);
val = digest_init (elem_type, empty_ctor, tf_warning_or_error);
+ }
+ else
+ val = build_value_init (elem_type, tf_warning_or_error);
+
+ if (!SCALAR_TYPE_P (elem_type))
+ {
new_ctx = *ctx;
- new_ctx.object = t;
+ if (ctx->object)
+ /* If there was no object, don't add one: it could confuse us
+ into thinking we're modifying a const object. */
+ new_ctx.object = t;
new_ctx.ctor = build_constructor (elem_type, NULL);
ctx = &new_ctx;
}
- else
- val = build_value_init (elem_type, tf_warning_or_error);
t = cxx_eval_constant_expression (ctx, val, lval, non_constant_p,
overflow_p);
- if (CP_AGGREGATE_TYPE_P (elem_type) && t != ctx->ctor)
+ if (!SCALAR_TYPE_P (elem_type) && t != ctx->ctor)
free_constructor (ctx->ctor);
return t;
}
@@ -4383,7 +4482,12 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value)
{
tree orig_value = value;
- init_subob_ctx (ctx, new_ctx, index, value);
+ /* Like in cxx_eval_store_expression, omit entries for empty fields. */
+ bool no_slot = TREE_CODE (type) == RECORD_TYPE && is_empty_field (index);
+ if (no_slot)
+ new_ctx = *ctx;
+ else
+ init_subob_ctx (ctx, new_ctx, index, value);
int pos_hint = -1;
if (new_ctx.ctor != ctx->ctor)
{
@@ -4429,6 +4533,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index))));
changed = true;
}
+ else if (no_slot)
+ changed = true;
else
{
if (TREE_CODE (type) == UNION_TYPE
@@ -4679,28 +4785,17 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
{
tree optype = TREE_TYPE (op);
unsigned HOST_WIDE_INT const_nunits;
- if (off == 0)
+ if (off == 0 && similar_type_p (optype, type))
+ return op;
+ else if (TREE_CODE (optype) == COMPLEX_TYPE
+ && similar_type_p (type, TREE_TYPE (optype)))
{
- if (similar_type_p (optype, type))
- return op;
- /* Also handle conversion to an empty base class, which
- is represented with a NOP_EXPR. */
/* *(foo *)&complexfoo => __real__ complexfoo */
- else if (TREE_CODE (optype) == COMPLEX_TYPE
- && similar_type_p (type, TREE_TYPE (optype)))
+ if (off == 0)
return build1_loc (loc, REALPART_EXPR, type, op);
- }
- /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
- else if (TREE_CODE (optype) == COMPLEX_TYPE
- && similar_type_p (type, TREE_TYPE (optype))
- && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off)
- return build1_loc (loc, IMAGPART_EXPR, type, op);
- if (is_empty_class (type)
- && CLASS_TYPE_P (optype)
- && DERIVED_FROM_P (type, optype))
- {
- *empty_base = true;
- return op;
+ /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+ else if (tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off)
+ return build1_loc (loc, IMAGPART_EXPR, type, op);
}
/* ((foo*)&vectorfoo)[x] => BIT_FIELD_REF<vectorfoo,...> */
else if (VECTOR_TYPE_P (optype)
@@ -4779,6 +4874,15 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
return ret;
}
}
+ /* Also handle conversion to an empty base class, which
+ is represented with a NOP_EXPR. */
+ if (is_empty_class (type)
+ && CLASS_TYPE_P (optype)
+ && DERIVED_FROM_P (type, optype))
+ {
+ *empty_base = true;
+ return op;
+ }
}
return NULL_TREE;
@@ -4839,12 +4943,26 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
&& tree_fits_uhwi_p (TREE_OPERAND (sub, 1)))
{
tree op00 = TREE_OPERAND (sub, 0);
- tree op01 = TREE_OPERAND (sub, 1);
+ tree off = TREE_OPERAND (sub, 1);
STRIP_NOPS (op00);
if (TREE_CODE (op00) == ADDR_EXPR)
- return cxx_fold_indirect_ref_1 (ctx, loc, type, TREE_OPERAND (op00, 0),
- tree_to_uhwi (op01), empty_base);
+ {
+ tree obj = TREE_OPERAND (op00, 0);
+ while (TREE_CODE (obj) == COMPONENT_REF
+ && tree_int_cst_sign_bit (off))
+ {
+ /* Canonicalize this object/offset pair by iteratively absorbing
+ the innermost component into the offset until the offset is
+ nonnegative, so that cxx_fold_indirect_ref_1 can identify
+ more folding opportunities. */
+ tree field = TREE_OPERAND (obj, 1);
+ off = int_const_binop (PLUS_EXPR, off, byte_position (field));
+ obj = TREE_OPERAND (obj, 0);
+ }
+ return cxx_fold_indirect_ref_1 (ctx, loc, type, obj,
+ tree_to_uhwi (off), empty_base);
+ }
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
@@ -5060,6 +5178,16 @@ var_in_constexpr_fn (tree t)
&& DECL_DECLARED_CONSTEXPR_P (ctx));
}
+/* True if a function might be constexpr: either a function that was
+ declared constexpr, or a C++17 lambda op(). */
+
+bool
+maybe_constexpr_fn (tree t)
+{
+ return (DECL_DECLARED_CONSTEXPR_P (t)
+ || (cxx_dialect >= cxx17 && LAMBDA_FUNCTION_P (t)));
+}
+
/* True if T was declared in a function that might be constexpr: either a
function that was declared constexpr, or a C++17 lambda op(). */
@@ -5405,9 +5533,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
semantics are not applied on an object under construction.
They come into effect when the constructor for the most
derived object ends." */
- tree elt;
- unsigned int i;
- FOR_EACH_VEC_ELT (*ctors, i, elt)
+ for (tree elt : *ctors)
if (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (const_object_being_modified), TREE_TYPE (elt)))
{
@@ -5474,8 +5600,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
argument, which has the derived type rather than the base type. In
this situation, just evaluate the initializer and return, since
there's no actual data to store. */
- gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval);
- return init;
+ gcc_assert (is_empty_class (TREE_TYPE (init)));
+ return lval ? target : init;
}
CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init);
TREE_CONSTANT (*valp) = TREE_CONSTANT (init);
@@ -5483,6 +5609,14 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
CONSTRUCTOR_NO_CLEARING (*valp)
= CONSTRUCTOR_NO_CLEARING (init);
}
+ else if (TREE_CODE (init) == CONSTRUCTOR
+ && !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init),
+ type))
+ {
+ /* See above on initialization of empty bases. */
+ gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval);
+ return init;
+ }
else
*valp = init;
@@ -5507,12 +5641,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
/* Update TREE_CONSTANT and TREE_SIDE_EFFECTS on enclosing
CONSTRUCTORs, if any. */
- tree elt;
- unsigned i;
bool c = TREE_CONSTANT (init);
bool s = TREE_SIDE_EFFECTS (init);
if (!c || s || activated_union_member_p)
- FOR_EACH_VEC_ELT (*ctors, i, elt)
+ for (tree elt : *ctors)
{
if (!c)
TREE_CONSTANT (elt) = false;
@@ -5697,7 +5829,6 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
- tree_stmt_iterator i;
tree local_target;
/* In a statement-expression we want to return the last value.
For empty statement expression return void_node. */
@@ -5707,9 +5838,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
local_target = NULL_TREE;
jump_target = &local_target;
}
- for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+ for (tree stmt : tsi_range (t))
{
- tree stmt = tsi_stmt (i);
/* We've found a continue, so skip everything until we reach
the label its jumping to. */
if (continues (jump_target))
@@ -5832,9 +5962,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
}
/* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */
- unsigned int i;
- tree save_expr;
- FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
+ for (tree save_expr : save_exprs)
ctx->global->values.remove (save_expr);
save_exprs.truncate (0);
@@ -5856,9 +5984,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
&& !*non_constant_p);
/* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */
- unsigned int i;
- tree save_expr;
- FOR_EACH_VEC_ELT (save_exprs, i, save_expr)
+ for (tree save_expr : save_exprs)
ctx->global->values.remove (save_expr);
return NULL_TREE;
@@ -5949,6 +6075,37 @@ inline_asm_in_constexpr_error (location_t loc)
"%<constexpr%> function in C++20");
}
+/* We're getting the constant value of DECL in a manifestly constant-evaluated
+ context; maybe complain about that. */
+
+static void
+maybe_warn_about_constant_value (location_t loc, tree decl)
+{
+ static bool explained = false;
+ if (cxx_dialect >= cxx17
+ && warn_interference_size
+ && !global_options_set.x_param_destruct_interfere_size
+ && DECL_CONTEXT (decl) == std_node
+ && id_equal (DECL_NAME (decl), "hardware_destructive_interference_size")
+ && (LOCATION_FILE (input_location) != main_input_filename
+ || module_exporting_p ())
+ && warning_at (loc, OPT_Winterference_size, "use of %qD", decl)
+ && !explained)
+ {
+ explained = true;
+ inform (loc, "its value can vary between compiler versions or "
+ "with different %<-mtune%> or %<-mcpu%> flags");
+ inform (loc, "if this use is part of a public ABI, change it to "
+ "instead use a constant variable you define");
+ inform (loc, "the default value for the current CPU tuning "
+ "is %d bytes", param_destruct_interfere_size);
+ inform (loc, "you can stabilize this value with %<--param "
+ "hardware_destructive_interference_size=%d%>, or disable "
+ "this warning with %<-Wno-interference-size%>",
+ param_destruct_interfere_size);
+ }
+}
+
/* Attempt to reduce the expression T to a constant value.
On failure, issue diagnostic and return error_mark_node. */
/* FIXME unify with c_fully_fold */
@@ -6093,6 +6250,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
r = *p;
break;
}
+ if (ctx->manifestly_const_eval)
+ maybe_warn_about_constant_value (loc, t);
if (COMPLETE_TYPE_P (TREE_TYPE (t))
&& is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false))
{
@@ -6656,7 +6815,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (t) == CONVERT_EXPR
&& ARITHMETIC_TYPE_P (type)
- && INDIRECT_TYPE_P (TREE_TYPE (op)))
+ && INDIRECT_TYPE_P (TREE_TYPE (op))
+ && ctx->manifestly_const_eval)
{
if (!ctx->quiet)
error_at (loc,
@@ -6669,8 +6829,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
/* [expr.const]: a conversion from type cv void* to a pointer-to-object
type cannot be part of a core constant expression as a resolution to
DR 1312. */
- if (integer_zerop (op) /* FIXME: Remove in GCC 12. */
- && TYPE_PTROB_P (type)
+ if (TYPE_PTROB_P (type)
&& TYPE_PTR_P (TREE_TYPE (op))
&& VOID_TYPE_P (TREE_TYPE (TREE_TYPE (op)))
/* Inside a call to std::construct_at or to
@@ -7319,6 +7478,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
}
}
+ /* Remember the original location if that wouldn't need a wrapper. */
+ if (location_t loc = EXPR_LOCATION (t))
+ if (CAN_HAVE_LOCATION_P (r))
+ SET_EXPR_LOCATION (r, loc);
+
return r;
}
@@ -7332,6 +7496,18 @@ cxx_constant_value (tree t, tree decl)
return cxx_eval_outermost_constant_expr (t, false, true, true, false, decl);
}
+/* As above, but respect SFINAE. */
+
+tree
+cxx_constant_value_sfinae (tree t, tsubst_flags_t complain)
+{
+ bool sfinae = !(complain & tf_error);
+ tree r = cxx_eval_outermost_constant_expr (t, sfinae, true, true);
+ if (sfinae && !TREE_CONSTANT (r))
+ r = error_mark_node;
+ return r;
+}
+
/* Like cxx_constant_value, but used for evaluation of constexpr destructors
of constexpr variables. The actual initializer of DECL is not modified. */
@@ -8207,16 +8383,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
}
case STATEMENT_LIST:
- {
- tree_stmt_iterator i;
- for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
- {
- if (!RECUR (tsi_stmt (i), any))
- return false;
- }
- return true;
- }
- break;
+ for (tree stmt : tsi_range (t))
+ if (!RECUR (stmt, any))
+ return false;
+ return true;
case MODIFY_EXPR:
if (cxx_dialect < cxx14)
@@ -8738,10 +8908,17 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
return false;
if (!processing_template_decl)
tmp = cxx_eval_outermost_constant_expr (tmp, true);
- if (integer_zerop (tmp))
- return RECUR (TREE_OPERAND (t, 2), want_rval);
- else if (TREE_CODE (tmp) == INTEGER_CST)
- return RECUR (TREE_OPERAND (t, 1), want_rval);
+ /* potential_constant_expression* isn't told if it is called for
+ manifestly_const_eval or not, so for consteval if always
+ process both branches as if the condition is not a known
+ constant. */
+ if (TREE_CODE (t) != IF_STMT || !IF_STMT_CONSTEVAL_P (t))
+ {
+ if (integer_zerop (tmp))
+ return RECUR (TREE_OPERAND (t, 2), want_rval);
+ else if (TREE_CODE (tmp) == INTEGER_CST)
+ return RECUR (TREE_OPERAND (t, 1), want_rval);
+ }
tmp = *jump_target;
for (i = 1; i < 3; ++i)
{