aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/constexpr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/constexpr.cc')
-rw-r--r--gcc/cp/constexpr.cc352
1 files changed, 254 insertions, 98 deletions
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 4346b29..f9066bc 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -303,11 +303,20 @@ is_valid_constexpr_fn (tree fun, bool complain)
}
}
}
- else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)))
+ else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)) && cxx_dialect < cxx26)
{
ret = false;
if (complain)
- error ("%q#T has virtual base classes", DECL_CONTEXT (fun));
+ {
+ if (DECL_CONSTRUCTOR_P (fun))
+ error ("%<constexpr%> constructor in %q#T that has "
+ "virtual base classes only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>", DECL_CONTEXT (fun));
+ else
+ error ("%<constexpr%> destructor in %q#T that has "
+ "virtual base classes only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>", DECL_CONTEXT (fun));
+ }
}
return ret;
@@ -1048,6 +1057,12 @@ explain_invalid_constexpr_fn (tree fun)
{
static hash_set<tree> *diagnosed;
tree body;
+
+ /* Don't try to explain a function we already complained about. */
+ if (function *f = DECL_STRUCT_FUNCTION (fun))
+ if (f->language->erroneous)
+ return;
+
/* In C++23, a function marked 'constexpr' may not actually be a constant
expression. We haven't diagnosed the problem yet: -Winvalid-constexpr
wasn't enabled. The function was called, so diagnose why it cannot be
@@ -1097,17 +1112,14 @@ explain_invalid_constexpr_fn (tree fun)
body = fd->body;
else
body = DECL_SAVED_TREE (fun);
- body = massage_constexpr_body (fun, body);
- require_potential_rvalue_constant_expression (body);
+ tree massaged = massage_constexpr_body (fun, body);
+ require_potential_rvalue_constant_expression (massaged);
if (DECL_CONSTRUCTOR_P (fun))
{
- cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true);
+ cx_check_missing_mem_inits (DECL_CONTEXT (fun), massaged, true);
if (cxx_dialect > cxx11)
- {
- /* Also check the body, not just the ctor-initializer. */
- body = DECL_SAVED_TREE (fun);
- require_potential_rvalue_constant_expression (body);
- }
+ /* Also check the body, not just the ctor-initializer. */
+ require_potential_rvalue_constant_expression (body);
}
}
}
@@ -1537,7 +1549,6 @@ static tree cxx_eval_bare_aggregate (const constexpr_ctx *, tree,
static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree,
bool * = NULL);
static tree find_heap_var_refs (tree *, int *, void *);
-static tree find_deleted_heap_var (tree *, int *, void *);
/* Attempt to evaluate T which represents a call to a builtin function.
We assume here that all builtin functions evaluate to scalar types
@@ -1870,20 +1881,28 @@ addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data)
static tree
cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
- bool *non_constant_p, bool *overflow_p,
- bool *non_constant_args)
+ tree orig_fun, bool *non_constant_p,
+ bool *overflow_p, bool *non_constant_args)
{
- const int nargs = call_expr_nargs (t);
+ int nargs = call_expr_nargs (t);
tree parms = DECL_ARGUMENTS (fun);
- int i;
+ int i, j = 0;
+ if (DECL_HAS_IN_CHARGE_PARM_P (fun) && fun != orig_fun)
+ ++nargs;
+ if (DECL_HAS_VTT_PARM_P (fun)
+ && fun != orig_fun
+ && (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun)
+ || DECL_COMPLETE_DESTRUCTOR_P (orig_fun)))
+ ++nargs;
/* We don't record ellipsis args below. */
int nparms = list_length (parms);
int nbinds = nargs < nparms ? nargs : nparms;
tree binds = make_tree_vec (nbinds);
/* The call is not a constant expression if it involves the cdtor for a type
- with virtual bases. */
- if (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun))
+ with virtual bases before C++26. */
+ if (cxx_dialect < cxx26
+ && (DECL_HAS_IN_CHARGE_PARM_P (fun) || DECL_HAS_VTT_PARM_P (fun)))
{
if (!ctx->quiet)
{
@@ -1901,7 +1920,30 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
tree type = parms ? TREE_TYPE (parms) : void_type_node;
if (parms && DECL_BY_REFERENCE (parms))
type = TREE_TYPE (type);
- x = get_nth_callarg (t, i);
+ if (i == 1
+ && j == 0
+ && DECL_HAS_IN_CHARGE_PARM_P (fun)
+ && orig_fun != fun)
+ {
+ if (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun)
+ || DECL_COMPLETE_DESTRUCTOR_P (orig_fun))
+ x = boolean_true_node;
+ else
+ x = boolean_false_node;
+ j = -1;
+ }
+ else if (i == 2
+ && j == -1
+ && DECL_HAS_VTT_PARM_P (fun)
+ && orig_fun != fun
+ && (DECL_COMPLETE_CONSTRUCTOR_P (orig_fun)
+ || DECL_COMPLETE_DESTRUCTOR_P (orig_fun)))
+ {
+ x = build_zero_cst (type);
+ j = -2;
+ }
+ else
+ x = get_nth_callarg (t, i + j);
/* For member function, the first argument is a pointer to the implied
object. For a constructor, it might still be a dummy object, in
which case we get the real argument from ctx. */
@@ -2520,10 +2562,7 @@ get_component_with_type (tree path, tree type, tree stop)
dst_ptr + src2dst == src_ptr
-1: unspecified relationship
-2: src_type is not a public base of dst_type
- -3: src_type is a multiple public non-virtual base of dst_type
-
- Since literal types can't have virtual bases, we only expect hint >=0,
- -2, or -3. */
+ -3: src_type is a multiple public non-virtual base of dst_type */
static tree
cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
@@ -2560,6 +2599,22 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
if (*non_constant_p)
return call;
+ /* For dynamic_cast from classes with virtual bases we can get something
+ like (virt_base *)(&d + 16) as OBJ. Try to convert that into
+ d.D.1234 using cxx_fold_indirect_ref. */
+ if (cxx_dialect >= cxx26 && CONVERT_EXPR_P (obj))
+ {
+ tree objo = obj;
+ STRIP_NOPS (objo);
+ if (TREE_CODE (objo) == POINTER_PLUS_EXPR)
+ {
+ objo = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (TREE_TYPE (obj)),
+ obj);
+ if (objo)
+ obj = build_fold_addr_expr (objo);
+ }
+ }
+
/* We expect OBJ to be in form of &d.D.2102 when HINT == 0,
but when HINT is > 0, it can also be something like
&d.D.2102 + 18446744073709551608, which includes the BINFO_OFFSET. */
@@ -2907,6 +2962,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
+ tree orig_fun = fun;
if (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun))
fun = DECL_CLONED_FUNCTION (fun);
@@ -2943,12 +2999,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
gcc_assert (arg0);
if (new_op_p)
{
- /* FIXME: We should not get here; the VERIFY_CONSTANT above
- should have already caught it. But currently a conversion
- from pointer type to arithmetic type is only considered
- non-constant for CONVERT_EXPRs, not NOP_EXPRs. */
if (!tree_fits_uhwi_p (arg0))
{
+ /* We should not get here; the VERIFY_CONSTANT above
+ should have already caught it. */
+ gcc_checking_assert (false);
if (!ctx->quiet)
error_at (loc, "cannot allocate array: size not constant");
*non_constant_p = true;
@@ -2963,14 +3018,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
: heap_uninit_identifier,
type);
DECL_ARTIFICIAL (var) = 1;
- TREE_STATIC (var) = 1;
- // Temporarily register the artificial var in varpool,
- // so that comparisons of its address against NULL are folded
- // through nonzero_address even with
- // -fno-delete-null-pointer-checks or that comparison of
- // addresses of different heap artificial vars is folded too.
- // See PR98988 and PR99031.
- varpool_node::finalize_decl (var);
ctx->global->heap_vars.safe_push (var);
ctx->global->put_value (var, NULL_TREE);
return fold_convert (ptr_type_node, build_address (var));
@@ -3079,6 +3126,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
}
constexpr_ctx new_ctx = *ctx;
+ ctx = &new_ctx;
if (DECL_CONSTRUCTOR_P (fun) && !ctx->object
&& TREE_CODE (t) == AGGR_INIT_EXPR)
{
@@ -3088,16 +3136,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL);
CONSTRUCTOR_NO_CLEARING (ctor) = true;
ctx->global->put_value (new_ctx.object, ctor);
- ctx = &new_ctx;
}
/* An immediate invocation is manifestly constant evaluated including the
arguments of the call, so use mce_true even for the argument
evaluation. */
if (DECL_IMMEDIATE_FUNCTION_P (fun))
- {
- new_ctx.manifestly_const_eval = mce_true;
- ctx = &new_ctx;
- }
+ new_ctx.manifestly_const_eval = mce_true;
/* We used to shortcut trivial constructor/op= here, but nowadays
we can only get a trivial function here with -fno-elide-constructors. */
@@ -3113,7 +3157,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
bool non_constant_args = false;
constexpr_call new_call;
new_call.bindings
- = cxx_bind_parameters_in_call (ctx, t, fun, non_constant_p,
+ = cxx_bind_parameters_in_call (ctx, t, fun, orig_fun, non_constant_p,
overflow_p, &non_constant_args);
/* We build up the bindings list before we know whether we already have this
@@ -3185,6 +3229,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
}
}
+ /* Don't complain about problems evaluating an ill-formed function. */
+ if (function *f = DECL_STRUCT_FUNCTION (fun))
+ if (f->language->erroneous)
+ new_ctx.quiet = true;
+
int depth_ok = push_cx_call_context (t);
/* Remember the object we are constructing or destructing. */
@@ -3440,11 +3489,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
cacheable = false;
break;
}
- /* And don't cache a ref to a deleted heap variable (119162). */
- if (cacheable
- && (cp_walk_tree_without_duplicates
- (&result, find_deleted_heap_var, NULL)))
- cacheable = false;
}
/* Rewrite all occurrences of the function's RESULT_DECL with the
@@ -3517,11 +3561,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
/* Return true if T is a valid constant initializer. If a CONSTRUCTOR
initializes all the members, the CONSTRUCTOR_NO_CLEARING flag will be
- cleared.
+ cleared. If called recursively on a FIELD_DECL's CONSTRUCTOR, SZ
+ is DECL_SIZE of the FIELD_DECL, otherwise NULL.
FIXME speed this up, it's taking 16% of compile time on sieve testcase. */
bool
-reduced_constant_expression_p (tree t)
+reduced_constant_expression_p (tree t, tree sz /* = NULL_TREE */)
{
if (t == NULL_TREE)
return false;
@@ -3532,6 +3577,9 @@ reduced_constant_expression_p (tree t)
/* Even if we can't lower this yet, it's constant. */
return true;
+ case OMP_DECLARE_MAPPER:
+ return true;
+
case CONSTRUCTOR:
/* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */
tree field;
@@ -3586,7 +3634,12 @@ reduced_constant_expression_p (tree t)
{
/* If VAL is null, we're in the middle of initializing this
element. */
- if (!reduced_constant_expression_p (e.value))
+ if (!reduced_constant_expression_p (e.value,
+ (e.index
+ && (TREE_CODE (e.index)
+ == FIELD_DECL))
+ ? DECL_SIZE (e.index)
+ : NULL_TREE))
return false;
/* We want to remove initializers for empty fields in a struct to
avoid confusing output_constructor. */
@@ -3606,7 +3659,16 @@ reduced_constant_expression_p (tree t)
/* There could be a non-empty field at the end. */
for (; field; field = next_subobject_field (DECL_CHAIN (field)))
if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false))
- return false;
+ {
+ /* Ignore FIELD_DECLs with bit positions beyond DECL_SIZE of
+ the parent FIELD_DECL (if any) for classes with virtual
+ bases. */
+ if (cxx_dialect >= cxx26
+ && sz
+ && tree_int_cst_le (sz, bit_position (field)))
+ break;
+ return false;
+ }
ok:
if (CONSTRUCTOR_NO_CLEARING (t))
/* All the fields are initialized. */
@@ -5868,6 +5930,20 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
unsigned HOST_WIDE_INT const_nunits;
if (off == 0 && similar_type_p (optype, type))
return op;
+ else if (cxx_dialect >= cxx26
+ && VAR_P (op)
+ && DECL_VTABLE_OR_VTT_P (op)
+ && same_type_ignoring_top_level_qualifiers_p (type,
+ ptrdiff_type_node)
+ && POINTER_TYPE_P (strip_array_types (optype)))
+ {
+ /* We often read some virtual table elements using ptrdiff_t rather
+ than pointer type. */
+ if (tree ret = cxx_fold_indirect_ref_1 (ctx, loc,
+ strip_array_types (optype),
+ op, off, empty_base))
+ return fold_convert (type, ret);
+ }
else if (TREE_CODE (optype) == COMPLEX_TYPE
&& similar_type_p (type, TREE_TYPE (optype)))
{
@@ -5961,8 +6037,13 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
if (!tree_fits_uhwi_p (pos))
continue;
unsigned HOST_WIDE_INT upos = tree_to_uhwi (pos);
- unsigned HOST_WIDE_INT el_sz
- = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+ unsigned HOST_WIDE_INT el_sz;
+ if (DECL_FIELD_IS_BASE (field)
+ && CLASS_TYPE_P (optype)
+ && CLASSTYPE_VBASECLASSES (optype))
+ el_sz = tree_to_uhwi (DECL_SIZE_UNIT (field));
+ else
+ el_sz = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
if (upos <= off && off < upos + el_sz)
{
tree cop = build3 (COMPONENT_REF, TREE_TYPE (field),
@@ -6013,6 +6094,25 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
offset positive, so that cxx_fold_indirect_ref_1 can identify
more folding opportunities. */
auto canonicalize_obj_off = [] (tree& obj, tree& off) {
+ if (cxx_dialect >= cxx26)
+ {
+ /* For C++26, we need to fold *(B *)(&x.D.1234 + 32) used
+ to access virtual base members. */
+ tree nobj = obj;
+ while (TREE_CODE (nobj) == COMPONENT_REF
+ && DECL_FIELD_IS_BASE (TREE_OPERAND (nobj, 1)))
+ nobj = TREE_OPERAND (nobj, 0);
+ if (nobj != obj
+ && CLASS_TYPE_P (TREE_TYPE (nobj))
+ && CLASSTYPE_VBASECLASSES (TREE_TYPE (nobj)))
+ while (obj != nobj)
+ {
+ tree field = TREE_OPERAND (obj, 1);
+ tree pos = byte_position (field);
+ off = int_const_binop (PLUS_EXPR, off, pos);
+ obj = TREE_OPERAND (obj, 0);
+ }
+ }
while (TREE_CODE (obj) == COMPONENT_REF
/* We need to preserve union member accesses so that we can
later properly diagnose accessing the wrong member. */
@@ -6051,8 +6151,8 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
{
tree off = integer_zero_node;
canonicalize_obj_off (op, off);
- gcc_assert (integer_zerop (off));
- return cxx_fold_indirect_ref_1 (ctx, loc, type, op, 0, empty_base);
+ return cxx_fold_indirect_ref_1 (ctx, loc, type, op,
+ tree_to_uhwi (off), empty_base);
}
}
else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
@@ -6413,7 +6513,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CLOBBER_P (init)
&& CLOBBER_KIND (init) < CLOBBER_OBJECT_END)
- /* Only handle clobbers ending the lifetime of objects. */
+ /* Only handle clobbers ending the lifetime of objects.
+ ??? We should probably set CONSTRUCTOR_NO_CLEARING. */
return void_node;
/* First we figure out where we're storing to. */
@@ -7841,6 +7942,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case LABEL_EXPR:
case CASE_LABEL_EXPR:
case PREDICT_EXPR:
+ case OMP_DECLARE_MAPPER:
return t;
case PARM_DECL:
@@ -8012,14 +8114,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
ctx->global->put_value (new_ctx.object, new_ctx.ctor);
ctx = &new_ctx;
}
+
+ /* If the initializer is complex, evaluate it to initialize slot. */
+ bool is_complex = target_expr_needs_replace (t);
+ if (is_complex)
+ /* In case no initialization actually happens, clear out any
+ void_node from a previous evaluation. */
+ ctx->global->put_value (slot, NULL_TREE);
+
/* Pass vc_prvalue because this indicates
initialization of a temporary. */
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue,
non_constant_p, overflow_p);
if (*non_constant_p)
break;
- /* If the initializer is complex, evaluate it to initialize slot. */
- bool is_complex = target_expr_needs_replace (t);
if (!is_complex)
{
r = unshare_constructor (r);
@@ -8464,7 +8572,7 @@ 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))
- && ctx->manifestly_const_eval == mce_true)
+ && ctx->strict)
{
if (!ctx->quiet)
error_at (loc,
@@ -8616,7 +8724,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
tree cookie_size = NULL_TREE;
tree arg_size = NULL_TREE;
if (TREE_CODE (elt_type) == RECORD_TYPE
- && TYPE_NAME (elt_type) == heap_identifier)
+ && TYPE_IDENTIFIER (elt_type) == heap_identifier)
{
tree fld1 = TYPE_FIELDS (elt_type);
tree fld2 = DECL_CHAIN (fld1);
@@ -9011,20 +9119,6 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/)
return NULL_TREE;
}
-/* Look for deleted heap variables in the expression *TP. */
-
-static tree
-find_deleted_heap_var (tree *tp, int *walk_subtrees, void */*data*/)
-{
- if (VAR_P (*tp)
- && DECL_NAME (*tp) == heap_deleted_identifier)
- return *tp;
-
- if (TYPE_P (*tp))
- *walk_subtrees = 0;
- return NULL_TREE;
-}
-
/* Find immediate function decls in *TP if any. */
static tree
@@ -9213,11 +9307,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (r == void_node && !constexpr_dtor && ctx.ctor)
r = ctx.ctor;
- if (!constexpr_dtor)
- verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
- else
- DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true;
-
unsigned int i;
tree cleanup;
/* Evaluate the cleanups. */
@@ -9236,15 +9325,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
non_constant_p = true;
}
- if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r))
- {
- if (!allow_non_constant)
- error ("%qE is not a constant expression because it refers to "
- "an incompletely initialized variable", t);
- TREE_CONSTANT (r) = false;
- non_constant_p = true;
- }
-
if (!non_constant_p && cxx_dialect >= cxx20
&& !global_ctx.heap_vars.is_empty ())
{
@@ -9254,9 +9334,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (heap_var)
{
if (!allow_non_constant && !non_constant_p)
- error_at (DECL_SOURCE_LOCATION (heap_var),
- "%qE is not a constant expression because it refers to "
- "a result of %<operator new%>", t);
+ {
+ error ("%qE is not a constant expression because it refers to "
+ "a result of %<operator new%>", t);
+ inform (DECL_SOURCE_LOCATION (heap_var), "allocated here");
+ }
r = t;
non_constant_p = true;
}
@@ -9265,13 +9347,14 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (DECL_NAME (heap_var) != heap_deleted_identifier)
{
if (!allow_non_constant && !non_constant_p)
- error_at (DECL_SOURCE_LOCATION (heap_var),
- "%qE is not a constant expression because allocated "
- "storage has not been deallocated", t);
+ {
+ error ("%qE is not a constant expression because allocated "
+ "storage has not been deallocated", t);
+ inform (DECL_SOURCE_LOCATION (heap_var), "allocated here");
+ }
r = t;
non_constant_p = true;
}
- varpool_node::get (heap_var)->remove ();
}
}
@@ -9297,6 +9380,20 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
non_constant_p = true;
}
+ if (!non_constant_p && !constexpr_dtor)
+ verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
+
+ /* After verify_constant because reduced_constant_expression_p can unset
+ CONSTRUCTOR_NO_CLEARING. */
+ if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r))
+ {
+ if (!allow_non_constant)
+ error ("%qE is not a constant expression because it refers to "
+ "an incompletely initialized variable", t);
+ TREE_CONSTANT (r) = false;
+ non_constant_p = true;
+ }
+
if (non_constant_p)
/* If we saw something bad, go back to our argument. The wrapping below is
only for the cases of TREE_CONSTANT argument or overflow. */
@@ -9313,13 +9410,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (non_constant_p && !allow_non_constant)
return error_mark_node;
- else if (constexpr_dtor)
- return r;
else if (non_constant_p && TREE_CONSTANT (r))
r = mark_non_constant (r);
else if (non_constant_p)
return t;
+ if (constexpr_dtor)
+ {
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true;
+ return r;
+ }
+
/* Check we are not trying to return the wrong type. */
if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (r)))
{
@@ -9471,6 +9572,9 @@ fold_simple (tree t)
tree
fold_to_constant (tree t)
{
+ if (processing_template_decl)
+ return t;
+
tree r = fold (t);
if (CONSTANT_CLASS_P (r) && !TREE_OVERFLOW (r))
return r;
@@ -9490,8 +9594,35 @@ tree
maybe_constant_value (tree t, tree decl /* = NULL_TREE */,
mce_value manifestly_const_eval /* = mce_unknown */)
{
+ tree orig_t = t;
tree r;
+ if (EXPR_P (t) && manifestly_const_eval == mce_unknown)
+ {
+ /* Look up each operand in the cv_cache first to see if we've already
+ reduced it, and reuse that result to avoid quadratic behavior if
+ we're called when building up a large expression. */
+ int n = cp_tree_operand_length (t);
+ tree *ops = XALLOCAVEC (tree, n);
+ bool rebuild = false;
+ for (int i = 0; i < n; ++i)
+ {
+ ops[i] = TREE_OPERAND (t, i);
+ if (tree *cached = hash_map_safe_get (cv_cache, ops[i]))
+ if (*cached != ops[i])
+ {
+ ops[i] = *cached;
+ rebuild = true;
+ }
+ }
+ if (rebuild)
+ {
+ t = copy_node (t);
+ for (int i = 0; i < n; ++i)
+ TREE_OPERAND (t, i) = ops[i];
+ }
+ }
+
if (!is_nondependent_constant_expression (t))
{
if (TREE_OVERFLOW_P (t)
@@ -9509,6 +9640,10 @@ maybe_constant_value (tree t, tree decl /* = NULL_TREE */,
return fold_to_constant (t);
if (manifestly_const_eval != mce_unknown)
+ /* TODO: Extend the cache to be mce_value aware. And if we have a
+ previously cached mce_unknown result that's TREE_CONSTANT, it means
+ the reduced value is independent of mce_value and so we should
+ be able to reuse it in the mce_true/false case. */
return cxx_eval_outermost_constant_expr (t, true, true,
manifestly_const_eval, false, decl);
@@ -9538,7 +9673,7 @@ maybe_constant_value (tree t, tree decl /* = NULL_TREE */,
|| (TREE_CONSTANT (t) && !TREE_CONSTANT (r))
|| !cp_tree_equal (r, t));
if (!c.evaluation_restricted_p ())
- cv_cache->put (t, r);
+ cv_cache->put (orig_t, r);
return r;
}
@@ -9728,16 +9863,26 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
{
/* [basic.start.static] allows constant-initialization of variables with
static or thread storage duration even if it isn't required, but we
- shouldn't bend the rules the same way for automatic variables. */
+ shouldn't bend the rules the same way for automatic variables.
+
+ But still enforce the requirements of constexpr/constinit.
+ [dcl.constinit] "If a variable declared with the constinit specifier
+ has dynamic initialization, the program is ill-formed, even if the
+ implementation would perform that initialization as a static
+ initialization." */
bool is_static = (decl && DECL_P (decl)
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)));
+ bool strict = (!is_static
+ || (decl && DECL_P (decl)
+ && (DECL_DECLARED_CONSTEXPR_P (decl)
+ || DECL_DECLARED_CONSTINIT_P (decl))));
if (is_static)
manifestly_const_eval = mce_true;
if (cp_unevaluated_operand && manifestly_const_eval != mce_true)
return fold_to_constant (t);
- t = cxx_eval_outermost_constant_expr (t, allow_non_constant, !is_static,
+ t = cxx_eval_outermost_constant_expr (t, allow_non_constant, strict,
manifestly_const_eval,
false, decl);
}
@@ -10528,6 +10673,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
"expression", t);
return false;
+ case OMP_DECLARE_MAPPER:
+ /* This can be used to initialize VAR_DECLs: it's treated as a magic
+ constant. */
+ return true;
+
case ASM_EXPR:
if (flags & tf_error)
inline_asm_in_constexpr_error (loc, fundef_p);
@@ -10975,6 +11125,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
*jump_target = *target;
return true;
}
+ if (DECL_ARTIFICIAL (*target))
+ /* The user didn't write this goto, this isn't the problem. */
+ return true;
if (flags & tf_error)
constexpr_error (loc, fundef_p, "%<goto%> is not a constant "
"expression");
@@ -11008,6 +11161,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case CO_AWAIT_EXPR:
case CO_YIELD_EXPR:
case CO_RETURN_EXPR:
+ if (flags & tf_error)
+ constexpr_error (cp_expr_loc_or_loc (t, input_location), fundef_p,
+ "%qE is not a constant expression", t);
return false;
/* Assume a TU-local entity is not constant, we'll error later when