[gcc/devel/rust/master] rust-constexpr.cc: port over cxx_eval_bare_aggregate. Comments out build_ctor_subob_ref inside init_
Thomas Schwinge
tschwinge@gcc.gnu.org
Mon Aug 29 15:34:25 GMT 2022
https://gcc.gnu.org/g:bbc514d024a232dacfe218706dd07dcf01a51314
commit bbc514d024a232dacfe218706dd07dcf01a51314
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date: Sat Aug 6 12:55:47 2022 +0100
rust-constexpr.cc: port over cxx_eval_bare_aggregate. Comments out build_ctor_subob_ref
inside init_subob_ctx.
Diff:
---
gcc/rust/backend/rust-constexpr.cc | 694 +++++++++++++++++++++++++------------
gcc/rust/backend/rust-tree.cc | 29 ++
gcc/rust/backend/rust-tree.h | 4 +
3 files changed, 503 insertions(+), 224 deletions(-)
diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index 3d7b8b0a73d..c26b1afcf66 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -990,6 +990,463 @@ inline_asm_in_constexpr_error (location_t loc)
"%<constexpr%> function in C++20");
}
+// forked from gcc/cp/constexpr.cc verify_ctor_sanity
+
+/* We're about to process an initializer for a class or array TYPE. Make
+ sure that CTX is set up appropriately. */
+
+static void
+verify_ctor_sanity (const constexpr_ctx *ctx, tree type)
+{
+ /* We don't bother building a ctor for an empty base subobject. */
+ if (is_empty_class (type))
+ return;
+
+ /* We're in the middle of an initializer that might involve placeholders;
+ our caller should have created a CONSTRUCTOR for us to put the
+ initializer into. We will either return that constructor or T. */
+ gcc_assert (ctx->ctor);
+ gcc_assert (
+ same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (ctx->ctor)));
+ /* We used to check that ctx->ctor was empty, but that isn't the case when
+ the object is zero-initialized before calling the constructor. */
+ if (ctx->object)
+ {
+ tree otype = TREE_TYPE (ctx->object);
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, otype)
+ /* Handle flexible array members. */
+ || (TREE_CODE (otype) == ARRAY_TYPE
+ && TYPE_DOMAIN (otype) == NULL_TREE
+ && TREE_CODE (type) == ARRAY_TYPE
+ && (same_type_ignoring_top_level_qualifiers_p (
+ TREE_TYPE (type), TREE_TYPE (otype)))));
+ }
+ gcc_assert (!ctx->object || !DECL_P (ctx->object)
+ || *(ctx->global->values.get (ctx->object)) == ctx->ctor);
+}
+
+// forked from gcc/cp/constexpr.cc array_index_cmp
+
+/* Some of the expressions fed to the constexpr mechanism are calls to
+ constructors, which have type void. In that case, return the type being
+ initialized by the constructor. */
+
+static tree
+initialized_type (tree t)
+{
+ if (TYPE_P (t))
+ return t;
+ tree type = TREE_TYPE (t);
+ if (TREE_CODE (t) == CALL_EXPR)
+ {
+ /* A constructor call has void type, so we need to look deeper. */
+ tree fn = get_function_named_in_call (t);
+ if (fn && TREE_CODE (fn) == FUNCTION_DECL && DECL_CXX_CONSTRUCTOR_P (fn))
+ type = DECL_CONTEXT (fn);
+ }
+ else if (TREE_CODE (t) == COMPOUND_EXPR)
+ return initialized_type (TREE_OPERAND (t, 1));
+
+ return cv_unqualified (type);
+}
+
+// forked from gcc/cp/constexpr.cc init_subob_ctx
+
+/* We're about to initialize element INDEX of an array or class from VALUE.
+ Set up NEW_CTX appropriately by adjusting .object to refer to the
+ subobject and creating a new CONSTRUCTOR if the element is itself
+ a class or array. */
+
+static void
+init_subob_ctx (const constexpr_ctx *ctx, constexpr_ctx &new_ctx, tree index,
+ tree &value)
+{
+ new_ctx = *ctx;
+
+ if (index && TREE_CODE (index) != INTEGER_CST
+ && TREE_CODE (index) != FIELD_DECL && TREE_CODE (index) != RANGE_EXPR)
+ /* This won't have an element in the new CONSTRUCTOR. */
+ return;
+
+ tree type = initialized_type (value);
+ if (!AGGREGATE_TYPE_P (type) && !VECTOR_TYPE_P (type))
+ /* A non-aggregate member doesn't get its own CONSTRUCTOR. */
+ return;
+
+ /* The sub-aggregate initializer might contain a placeholder;
+ update object to refer to the subobject and ctor to refer to
+ the (newly created) sub-initializer. */
+ if (ctx->object)
+ {
+ if (index == NULL_TREE || TREE_CODE (index) == RANGE_EXPR)
+ /* There's no well-defined subobject for this index. */
+ new_ctx.object = NULL_TREE;
+ else
+ // new_ctx.object = build_ctor_subob_ref (index, type, ctx->object);
+ ;
+ }
+ tree elt = build_constructor (type, NULL);
+ CONSTRUCTOR_NO_CLEARING (elt) = true;
+ new_ctx.ctor = elt;
+
+ if (TREE_CODE (value) == TARGET_EXPR)
+ /* Avoid creating another CONSTRUCTOR when we expand the TARGET_EXPR. */
+ value = TARGET_EXPR_INITIAL (value);
+}
+
+// forked from gcc/cp/constexpr.cc base_field_constructor_elt
+
+/* REF is a COMPONENT_REF designating a particular field. V is a vector of
+ CONSTRUCTOR elements to initialize (part of) an object containing that
+ field. Return a pointer to the constructor_elt corresponding to the
+ initialization of the field. */
+
+static constructor_elt *
+base_field_constructor_elt (vec<constructor_elt, va_gc> *v, tree ref)
+{
+ tree aggr = TREE_OPERAND (ref, 0);
+ tree field = TREE_OPERAND (ref, 1);
+ HOST_WIDE_INT i;
+ constructor_elt *ce;
+
+ gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
+
+ if (TREE_CODE (aggr) == COMPONENT_REF)
+ {
+ constructor_elt *base_ce = base_field_constructor_elt (v, aggr);
+ v = CONSTRUCTOR_ELTS (base_ce->value);
+ }
+
+ for (i = 0; vec_safe_iterate (v, i, &ce); ++i)
+ if (ce->index == field)
+ return ce;
+
+ gcc_unreachable ();
+ return NULL;
+}
+
+/* Return a pointer to the constructor_elt of CTOR which matches INDEX. If no
+ matching constructor_elt exists, then add one to CTOR.
+
+ As an optimization, if POS_HINT is non-negative then it is used as a guess
+ for the (integer) index of the matching constructor_elt within CTOR. */
+
+static constructor_elt *
+get_or_insert_ctor_field (tree ctor, tree index, int pos_hint = -1)
+{
+ /* Check the hint first. */
+ if (pos_hint >= 0 && (unsigned) pos_hint < CONSTRUCTOR_NELTS (ctor)
+ && CONSTRUCTOR_ELT (ctor, pos_hint)->index == index)
+ return CONSTRUCTOR_ELT (ctor, pos_hint);
+
+ tree type = TREE_TYPE (ctor);
+ if (TREE_CODE (type) == VECTOR_TYPE && index == NULL_TREE)
+ {
+ CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (ctor), index, NULL_TREE);
+ return &CONSTRUCTOR_ELTS (ctor)->last ();
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (TREE_CODE (index) == RANGE_EXPR)
+ {
+ /* Support for RANGE_EXPR index lookups is currently limited to
+ accessing an existing element via POS_HINT, or appending a new
+ element to the end of CTOR. ??? Support for other access
+ patterns may also be needed. */
+ vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
+ if (vec_safe_length (elts))
+ {
+ tree lo = TREE_OPERAND (index, 0);
+ gcc_assert (array_index_cmp (elts->last ().index, lo) < 0);
+ }
+ CONSTRUCTOR_APPEND_ELT (elts, index, NULL_TREE);
+ return &elts->last ();
+ }
+
+ HOST_WIDE_INT i = find_array_ctor_elt (ctor, index, /*insert*/ true);
+ gcc_assert (i >= 0);
+ constructor_elt *cep = CONSTRUCTOR_ELT (ctor, i);
+ gcc_assert (cep->index == NULL_TREE
+ || TREE_CODE (cep->index) != RANGE_EXPR);
+ return cep;
+ }
+ else
+ {
+ gcc_assert (
+ TREE_CODE (index) == FIELD_DECL
+ && (same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (index),
+ TREE_TYPE (ctor))));
+
+ /* We must keep the CONSTRUCTOR's ELTS in FIELD order.
+ Usually we meet initializers in that order, but it is
+ possible for base types to be placed not in program
+ order. */
+ tree fields = TYPE_FIELDS (DECL_CONTEXT (index));
+ unsigned HOST_WIDE_INT idx = 0;
+ constructor_elt *cep = NULL;
+
+ /* Check if we're changing the active member of a union. */
+ if (TREE_CODE (type) == UNION_TYPE && CONSTRUCTOR_NELTS (ctor)
+ && CONSTRUCTOR_ELT (ctor, 0)->index != index)
+ vec_safe_truncate (CONSTRUCTOR_ELTS (ctor), 0);
+ /* If the bit offset of INDEX is larger than that of the last
+ constructor_elt, then we can just immediately append a new
+ constructor_elt to the end of CTOR. */
+ else if (CONSTRUCTOR_NELTS (ctor)
+ && tree_int_cst_compare (
+ bit_position (index),
+ bit_position (CONSTRUCTOR_ELTS (ctor)->last ().index))
+ > 0)
+ {
+ idx = CONSTRUCTOR_NELTS (ctor);
+ goto insert;
+ }
+
+ /* Otherwise, we need to iterate over CTOR to find or insert INDEX
+ appropriately. */
+
+ for (; vec_safe_iterate (CONSTRUCTOR_ELTS (ctor), idx, &cep);
+ idx++, fields = DECL_CHAIN (fields))
+ {
+ if (index == cep->index)
+ goto found;
+
+ /* The field we're initializing must be on the field
+ list. Look to see if it is present before the
+ field the current ELT initializes. */
+ for (; fields != cep->index; fields = DECL_CHAIN (fields))
+ if (index == fields)
+ goto insert;
+ }
+ /* We fell off the end of the CONSTRUCTOR, so insert a new
+ entry at the end. */
+
+ insert : {
+ constructor_elt ce = {index, NULL_TREE};
+
+ vec_safe_insert (CONSTRUCTOR_ELTS (ctor), idx, ce);
+ cep = CONSTRUCTOR_ELT (ctor, idx);
+ }
+ found:;
+
+ return cep;
+ }
+}
+
+// forked from gcc/cp/constexpr.cc cxx_eval_bare_aggregate
+
+/* Subroutine of cxx_eval_constant_expression.
+ The expression tree T denotes a C-style array or a C-style
+ aggregate. Reduce it to a constant expression. */
+
+static tree
+eval_bare_aggregate (const constexpr_ctx *ctx, tree t, bool lval,
+ bool *non_constant_p, bool *overflow_p)
+{
+ vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t);
+ bool changed = false;
+ gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (t));
+ tree type = TREE_TYPE (t);
+
+ constexpr_ctx new_ctx;
+ if (TYPE_PTRMEMFUNC_P (type) || VECTOR_TYPE_P (type))
+ {
+ /* We don't really need the ctx->ctor business for a PMF or
+ vector, but it's simpler to use the same code. */
+ new_ctx = *ctx;
+ new_ctx.ctor = build_constructor (type, NULL);
+ new_ctx.object = NULL_TREE;
+ ctx = &new_ctx;
+ };
+ verify_ctor_sanity (ctx, type);
+ vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor);
+ vec_alloc (*p, vec_safe_length (v));
+
+ if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (t))
+ CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ctx->ctor) = 1;
+
+ unsigned i;
+ tree index, value;
+ bool constant_p = true;
+ bool side_effects_p = false;
+ FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value)
+ {
+ tree orig_value = 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)
+ {
+ /* If we built a new CONSTRUCTOR, attach it now so that other
+ initializers can refer to it. */
+ constructor_elt *cep = get_or_insert_ctor_field (ctx->ctor, index);
+ cep->value = new_ctx.ctor;
+ pos_hint = cep - (*p)->begin ();
+ }
+ else if (TREE_CODE (type) == UNION_TYPE)
+ /* Otherwise if we're constructing a non-aggregate union member, set
+ the active union member now so that we can later detect and diagnose
+ if its initializer attempts to activate another member. */
+ get_or_insert_ctor_field (ctx->ctor, index);
+ tree elt = eval_constant_expression (&new_ctx, value, lval,
+ non_constant_p, overflow_p);
+ /* Don't VERIFY_CONSTANT here. */
+ if (ctx->quiet && *non_constant_p)
+ break;
+ if (elt != orig_value)
+ changed = true;
+
+ if (!TREE_CONSTANT (elt))
+ constant_p = false;
+ if (TREE_SIDE_EFFECTS (elt))
+ side_effects_p = true;
+ if (index && TREE_CODE (index) == COMPONENT_REF)
+ {
+ /* This is an initialization of a vfield inside a base
+ subaggregate that we already initialized; push this
+ initialization into the previous initialization. */
+ constructor_elt *inner = base_field_constructor_elt (*p, index);
+ inner->value = elt;
+ changed = true;
+ }
+ else if (index
+ && (TREE_CODE (index) == NOP_EXPR
+ || TREE_CODE (index) == POINTER_PLUS_EXPR))
+ {
+ /* This is an initializer for an empty base; now that we've
+ checked that it's constant, we can ignore it. */
+ 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 && (*p)->last ().index != index)
+ /* The initializer erroneously changed the active union member that
+ we're initializing. */
+ gcc_assert (*non_constant_p);
+ else
+ {
+ /* The initializer might have mutated the underlying CONSTRUCTOR,
+ so recompute the location of the target constructer_elt. */
+ constructor_elt *cep
+ = get_or_insert_ctor_field (ctx->ctor, index, pos_hint);
+ cep->value = elt;
+ }
+
+ /* Adding or replacing an element might change the ctor's flags. */
+ TREE_CONSTANT (ctx->ctor) = constant_p;
+ TREE_SIDE_EFFECTS (ctx->ctor) = side_effects_p;
+ }
+ }
+ if (*non_constant_p || !changed)
+ return t;
+ t = ctx->ctor;
+ /* We're done building this CONSTRUCTOR, so now we can interpret an
+ element without an explicit initializer as value-initialized. */
+ CONSTRUCTOR_NO_CLEARING (t) = false;
+ TREE_CONSTANT (t) = constant_p;
+ TREE_SIDE_EFFECTS (t) = side_effects_p;
+ if (VECTOR_TYPE_P (type))
+ t = fold (t);
+ return 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.
+ FIXME speed this up, it's taking 16% of compile time on sieve testcase. */
+
+bool
+reduced_constant_expression_p (tree t)
+{
+ if (t == NULL_TREE)
+ return false;
+
+ switch (TREE_CODE (t))
+ {
+ case PTRMEM_CST:
+ /* Even if we can't lower this yet, it's constant. */
+ return true;
+
+ case CONSTRUCTOR:
+ /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */
+ tree field;
+ if (CONSTRUCTOR_NO_CLEARING (t))
+ {
+ if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+ /* An initialized vector would have a VECTOR_CST. */
+ return false;
+ else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+ {
+ /* 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 (auto &e : CONSTRUCTOR_ELTS (t))
+ {
+ if (!reduced_constant_expression_p (e.value))
+ return false;
+ if (array_index_cmp (cursor, e.index) != 0)
+ return false;
+ if (TREE_CODE (e.index) == RANGE_EXPR)
+ cursor = TREE_OPERAND (e.index, 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 (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
+ {
+ if (CONSTRUCTOR_NELTS (t) == 0)
+ /* An initialized union has a constructor element. */
+ return false;
+ /* And it only initializes one member. */
+ field = NULL_TREE;
+ }
+ else
+ field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)));
+ }
+ else
+ field = NULL_TREE;
+ for (auto &e : CONSTRUCTOR_ELTS (t))
+ {
+ /* If VAL is null, we're in the middle of initializing this
+ element. */
+ if (!reduced_constant_expression_p (e.value))
+ return false;
+ /* Empty class field may or may not have an initializer. */
+ for (; field && e.index != field;
+ field = next_initializable_field (DECL_CHAIN (field)))
+ if (!is_really_empty_class (TREE_TYPE (field),
+ /*ignore_vptr*/ false))
+ return false;
+ if (field)
+ field = next_initializable_field (DECL_CHAIN (field));
+ }
+ /* There could be a non-empty field at the end. */
+ 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;
+ return true;
+
+ default:
+ /* FIXME are we calling this too much? */
+ return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
+ }
+}
+
static tree
eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
bool *non_constant_p, bool *overflow_p,
@@ -1276,7 +1733,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
break;
case COND_EXPR:
- case IF_STMT:
+ case IF_STMT: // comes from cp-tree.def
if (jump_target && *jump_target)
{
tree orig_jump = *jump_target;
@@ -1315,6 +1772,18 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
jump_target);
break;
+ case CONSTRUCTOR:
+ if (TREE_CONSTANT (t) && reduced_constant_expression_p (t))
+ {
+ /* Don't re-process a constant CONSTRUCTOR, but do fold it to
+ VECTOR_CST if applicable. */
+ verify_constructor_flags (t);
+ if (TREE_CONSTANT (t))
+ return fold (t);
+ }
+ r = eval_bare_aggregate (ctx, t, lval, non_constant_p, overflow_p);
+ break;
+
/* FALLTHROUGH. */
case CONVERT_EXPR:
case VIEW_CONVERT_EXPR: {
@@ -1479,114 +1948,6 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
return r;
}
-/* Return a pointer to the constructor_elt of CTOR which matches INDEX. If no
- matching constructor_elt exists, then add one to CTOR.
-
- As an optimization, if POS_HINT is non-negative then it is used as a guess
- for the (integer) index of the matching constructor_elt within CTOR. */
-
-static constructor_elt *
-get_or_insert_ctor_field (tree ctor, tree index, int pos_hint = -1)
-{
- /* Check the hint first. */
- if (pos_hint >= 0 && (unsigned) pos_hint < CONSTRUCTOR_NELTS (ctor)
- && CONSTRUCTOR_ELT (ctor, pos_hint)->index == index)
- return CONSTRUCTOR_ELT (ctor, pos_hint);
-
- tree type = TREE_TYPE (ctor);
- if (TREE_CODE (type) == VECTOR_TYPE && index == NULL_TREE)
- {
- CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (ctor), index, NULL_TREE);
- return &CONSTRUCTOR_ELTS (ctor)->last ();
- }
- else if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == VECTOR_TYPE)
- {
- if (TREE_CODE (index) == RANGE_EXPR)
- {
- /* Support for RANGE_EXPR index lookups is currently limited to
- accessing an existing element via POS_HINT, or appending a new
- element to the end of CTOR. ??? Support for other access
- patterns may also be needed. */
- vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
- if (vec_safe_length (elts))
- {
- tree lo = TREE_OPERAND (index, 0);
- gcc_assert (array_index_cmp (elts->last ().index, lo) < 0);
- }
- CONSTRUCTOR_APPEND_ELT (elts, index, NULL_TREE);
- return &elts->last ();
- }
-
- HOST_WIDE_INT i = find_array_ctor_elt (ctor, index, /*insert*/ true);
- gcc_assert (i >= 0);
- constructor_elt *cep = CONSTRUCTOR_ELT (ctor, i);
- gcc_assert (cep->index == NULL_TREE
- || TREE_CODE (cep->index) != RANGE_EXPR);
- return cep;
- }
- else
- {
- gcc_assert (
- TREE_CODE (index) == FIELD_DECL
- && (same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (index),
- TREE_TYPE (ctor))));
-
- /* We must keep the CONSTRUCTOR's ELTS in FIELD order.
- Usually we meet initializers in that order, but it is
- possible for base types to be placed not in program
- order. */
- tree fields = TYPE_FIELDS (DECL_CONTEXT (index));
- unsigned HOST_WIDE_INT idx = 0;
- constructor_elt *cep = NULL;
-
- /* Check if we're changing the active member of a union. */
- if (TREE_CODE (type) == UNION_TYPE && CONSTRUCTOR_NELTS (ctor)
- && CONSTRUCTOR_ELT (ctor, 0)->index != index)
- vec_safe_truncate (CONSTRUCTOR_ELTS (ctor), 0);
- /* If the bit offset of INDEX is larger than that of the last
- constructor_elt, then we can just immediately append a new
- constructor_elt to the end of CTOR. */
- else if (CONSTRUCTOR_NELTS (ctor)
- && tree_int_cst_compare (
- bit_position (index),
- bit_position (CONSTRUCTOR_ELTS (ctor)->last ().index))
- > 0)
- {
- idx = CONSTRUCTOR_NELTS (ctor);
- goto insert;
- }
-
- /* Otherwise, we need to iterate over CTOR to find or insert INDEX
- appropriately. */
-
- for (; vec_safe_iterate (CONSTRUCTOR_ELTS (ctor), idx, &cep);
- idx++, fields = DECL_CHAIN (fields))
- {
- if (index == cep->index)
- goto found;
-
- /* The field we're initializing must be on the field
- list. Look to see if it is present before the
- field the current ELT initializes. */
- for (; fields != cep->index; fields = DECL_CHAIN (fields))
- if (index == fields)
- goto insert;
- }
- /* We fell off the end of the CONSTRUCTOR, so insert a new
- entry at the end. */
-
- insert : {
- constructor_elt ce = {index, NULL_TREE};
-
- vec_safe_insert (CONSTRUCTOR_ELTS (ctor), idx, ce);
- cep = CONSTRUCTOR_ELT (ctor, idx);
- }
- found:;
-
- return cep;
- }
-}
-
/* Complain about a const object OBJ being modified in a constant expression.
EXPR is the MODIFY_EXPR expression performing the modification. */
@@ -2617,31 +2978,6 @@ var_in_maybe_constexpr_fn (tree t)
return (DECL_FUNCTION_SCOPE_P (t) && maybe_constexpr_fn (DECL_CONTEXT (t)));
}
-// forked from gcc/cp/constexpr.cc array_index_cmp
-
-/* Some of the expressions fed to the constexpr mechanism are calls to
- constructors, which have type void. In that case, return the type being
- initialized by the constructor. */
-
-static tree
-initialized_type (tree t)
-{
- if (TYPE_P (t))
- return t;
- tree type = TREE_TYPE (t);
- if (TREE_CODE (t) == CALL_EXPR)
- {
- /* A constructor call has void type, so we need to look deeper. */
- tree fn = get_function_named_in_call (t);
- if (fn && TREE_CODE (fn) == FUNCTION_DECL && DECL_CXX_CONSTRUCTOR_P (fn))
- type = DECL_CONTEXT (fn);
- }
- else if (TREE_CODE (t) == COMPOUND_EXPR)
- return initialized_type (TREE_OPERAND (t, 1));
-
- return cv_unqualified (type);
-}
-
/* P0859: A function is needed for constant evaluation if it is a constexpr
function that is named by an expression ([basic.def.odr]) that is
potentially constant evaluated.
@@ -2854,96 +3190,6 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert)
return -1;
}
-/* Return true if T is a valid constant initializer. If a CONSTRUCTOR
- initializes all the members, the CONSTRUCTOR_NO_CLEARING flag will be
- cleared.
- FIXME speed this up, it's taking 16% of compile time on sieve testcase. */
-
-bool
-reduced_constant_expression_p (tree t)
-{
- if (t == NULL_TREE)
- return false;
-
- switch (TREE_CODE (t))
- {
- case PTRMEM_CST:
- /* Even if we can't lower this yet, it's constant. */
- return true;
-
- case CONSTRUCTOR:
- /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */
- tree field;
- if (CONSTRUCTOR_NO_CLEARING (t))
- {
- if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
- /* An initialized vector would have a VECTOR_CST. */
- return false;
- else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
- {
- /* 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 (auto &e : CONSTRUCTOR_ELTS (t))
- {
- if (!reduced_constant_expression_p (e.value))
- return false;
- if (array_index_cmp (cursor, e.index) != 0)
- return false;
- if (TREE_CODE (e.index) == RANGE_EXPR)
- cursor = TREE_OPERAND (e.index, 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 (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
- {
- if (CONSTRUCTOR_NELTS (t) == 0)
- /* An initialized union has a constructor element. */
- return false;
- /* And it only initializes one member. */
- field = NULL_TREE;
- }
- else
- field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)));
- }
- else
- field = NULL_TREE;
- for (auto &e : CONSTRUCTOR_ELTS (t))
- {
- /* If VAL is null, we're in the middle of initializing this
- element. */
- if (!reduced_constant_expression_p (e.value))
- return false;
- /* Empty class field may or may not have an initializer. */
- for (; field && e.index != field;
- field = next_initializable_field (DECL_CHAIN (field)))
- if (!is_really_empty_class (TREE_TYPE (field),
- /*ignore_vptr*/ false))
- return false;
- if (field)
- field = next_initializable_field (DECL_CHAIN (field));
- }
- /* There could be a non-empty field at the end. */
- 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;
- return true;
-
- default:
- /* FIXME are we calling this too much? */
- return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
- }
-}
-
/* Some expressions may have constant operands but are not constant
themselves, such as 1/0. Call this function to check for that
condition.
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 82b58459d6f..289b4b95801 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -4079,4 +4079,33 @@ build_new_constexpr_heap_type (tree elt_type, tree cookie_size, tree full_size)
return rtype;
}
+// forked from gcc/cp/class.cc field_poverlapping_p
+
+/* Return true iff FIELD_DECL DECL is potentially overlapping. */
+
+static bool
+field_poverlapping_p (tree decl)
+{
+ return lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (decl));
+}
+
+// forked from gcc/cp/class.cc is_empty_field
+
+/* Return true iff DECL is an empty field, either for an empty base or a
+ [[no_unique_address]] data member. */
+
+bool
+is_empty_field (tree decl)
+{
+ if (!decl || TREE_CODE (decl) != FIELD_DECL)
+ return false;
+
+ bool r = (is_empty_class (TREE_TYPE (decl)) && (field_poverlapping_p (decl)));
+
+ /* Empty fields should have size zero. */
+ gcc_checking_assert (!r || integer_zerop (DECL_SIZE (decl)));
+
+ return r;
+}
+
} // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 966dbebf30c..f466a81962e 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -1269,6 +1269,8 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
#define CONSTRUCTOR_PLACEHOLDER_BOUNDARY(NODE) \
(TREE_LANG_FLAG_5 (CONSTRUCTOR_CHECK (NODE)))
+#define AGGR_INIT_EXPR_SLOT(NODE) TREE_OPERAND (AGGR_INIT_EXPR_CHECK (NODE), 2)
+
#if defined ENABLE_TREE_CHECKING
#define LANG_DECL_MIN_CHECK(NODE) \
@@ -2605,6 +2607,8 @@ extern bool decl_constant_var_p (tree);
extern tree build_new_constexpr_heap_type (tree, tree, tree);
+extern bool is_empty_field (tree);
+
// forked from gcc/cp/cp-tree.h
enum
More information about the Gcc-cvs
mailing list