aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-constexpr.cc
diff options
context:
space:
mode:
authorFaisal Abbas <90.abbasfaisal@gmail.com>2022-08-16 12:40:33 +0100
committerPhilip Herron <philip.herron@embecosm.com>2022-08-25 12:40:28 +0100
commit4ca228d2f32e5eb6e9516f487be85383225d5a00 (patch)
treee2e870e7baea1e918a9757db8ad6c1e456077ebc /gcc/rust/backend/rust-constexpr.cc
parentdebe4aedc76a1f52c3072254b6be4da4f4c4696c (diff)
downloadgcc-4ca228d2f32e5eb6e9516f487be85383225d5a00.zip
gcc-4ca228d2f32e5eb6e9516f487be85383225d5a00.tar.gz
gcc-4ca228d2f32e5eb6e9516f487be85383225d5a00.tar.bz2
rust-constexpr.cc: port over cxx_eval_array_reference and
cxx_eval_component_reference. Some important parts are commented out and marked such. These will need revisiting.
Diffstat (limited to 'gcc/rust/backend/rust-constexpr.cc')
-rw-r--r--gcc/rust/backend/rust-constexpr.cc327
1 files changed, 301 insertions, 26 deletions
diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index 5ac12d2..c0194db 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -1532,6 +1532,273 @@ adjust_temp_type (tree type, tree temp)
return fold_convert (cv_unqualified (type), temp);
}
+// forked from gcc/cp/constexpr.cc free_constructor
+
+/* If T is a CONSTRUCTOR, ggc_free T and any sub-CONSTRUCTORs. */
+
+static void
+free_constructor (tree t)
+{
+ if (!t || TREE_CODE (t) != CONSTRUCTOR)
+ return;
+ releasing_vec ctors;
+ vec_safe_push (ctors, t);
+ while (!ctors->is_empty ())
+ {
+ tree c = ctors->pop ();
+ if (vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (c))
+ {
+ constructor_elt *ce;
+ for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i)
+ if (TREE_CODE (ce->value) == CONSTRUCTOR)
+ vec_safe_push (ctors, ce->value);
+ ggc_free (elts);
+ }
+ ggc_free (c);
+ }
+}
+
+static tree
+eval_and_check_array_index (const constexpr_ctx *ctx, tree t,
+ bool allow_one_past, bool *non_constant_p,
+ bool *overflow_p);
+
+// forked from gcc/cp/constexpr.cc cxx_eval_array_reference
+
+/* Subroutine of cxx_eval_constant_expression.
+ Attempt to reduce a reference to an array slot. */
+
+static tree
+eval_array_reference (const constexpr_ctx *ctx, tree t, bool lval,
+ bool *non_constant_p, bool *overflow_p)
+{
+ tree oldary = TREE_OPERAND (t, 0);
+ tree ary
+ = eval_constant_expression (ctx, oldary, lval, non_constant_p, overflow_p);
+ if (*non_constant_p)
+ return t;
+ if (!lval && TREE_CODE (ary) == VIEW_CONVERT_EXPR
+ && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
+ && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0))))
+ ary = TREE_OPERAND (ary, 0);
+
+ tree oldidx = TREE_OPERAND (t, 1);
+ tree index
+ = eval_and_check_array_index (ctx, t, lval, non_constant_p, overflow_p);
+ if (*non_constant_p)
+ return t;
+
+ if (lval && ary == oldary && index == oldidx)
+ return t;
+ else if (lval)
+ return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
+
+ unsigned len = 0, elem_nchars = 1;
+ tree elem_type = TREE_TYPE (TREE_TYPE (ary));
+ if (TREE_CODE (ary) == CONSTRUCTOR)
+ len = CONSTRUCTOR_NELTS (ary);
+ else if (TREE_CODE (ary) == STRING_CST)
+ {
+ elem_nchars
+ = (TYPE_PRECISION (elem_type) / TYPE_PRECISION (char_type_node));
+ len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
+ }
+ else if (TREE_CODE (ary) == VECTOR_CST)
+ /* We don't create variable-length VECTOR_CSTs. */
+ len = VECTOR_CST_NELTS (ary).to_constant ();
+ else
+ {
+ /* We can't do anything with other tree codes, so use
+ VERIFY_CONSTANT to complain and fail. */
+ VERIFY_CONSTANT (ary);
+ gcc_unreachable ();
+ }
+
+ bool found;
+ HOST_WIDE_INT i = 0;
+ if (TREE_CODE (ary) == CONSTRUCTOR)
+ {
+ HOST_WIDE_INT ix = find_array_ctor_elt (ary, index);
+ found = (ix >= 0);
+ if (found)
+ i = ix;
+ }
+ else
+ {
+ i = tree_to_shwi (index);
+ found = (i < len);
+ }
+
+ if (found)
+ {
+ tree r;
+ if (TREE_CODE (ary) == CONSTRUCTOR)
+ r = (*CONSTRUCTOR_ELTS (ary))[i].value;
+ else if (TREE_CODE (ary) == VECTOR_CST)
+ r = VECTOR_CST_ELT (ary, i);
+ else
+ r = extract_string_elt (ary, elem_nchars, i);
+
+ if (r)
+ /* Don't VERIFY_CONSTANT here. */
+ return r;
+
+ /* Otherwise the element doesn't have a value yet. */
+ }
+
+ /* Not found. */
+
+ if (TREE_CODE (ary) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (ary))
+ {
+ /* 'ary' is part of the aggregate initializer we're currently
+ building; if there's no initializer for this element yet,
+ that's an error. */
+ if (!ctx->quiet)
+ error ("accessing uninitialized array element");
+ *non_constant_p = true;
+ return t;
+ }
+
+ /* If it's within the array bounds but doesn't have an explicit
+ initializer, it's initialized from {}. But use build_value_init
+ directly for non-aggregates to avoid creating a garbage CONSTRUCTOR. */
+ tree val;
+ constexpr_ctx new_ctx;
+ if (is_really_empty_class (elem_type, /*ignore_vptr*/ false))
+ return build_constructor (elem_type, NULL);
+ // Faisal: commenting this out as not sure if we need this but we need to come
+ // back to handle this to assign suitable value to val before sending it in
+ // eval_constant_expression below
+ // 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;
+ 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;
+ }
+ t = eval_constant_expression (ctx, val, lval, non_constant_p, overflow_p);
+ if (!SCALAR_TYPE_P (elem_type) && t != ctx->ctor)
+ free_constructor (ctx->ctor);
+ return t;
+}
+
+// forked from gcc/cp/constexpr.cc cxx_eval_component_reference
+
+/* Subroutine of cxx_eval_constant_expression.
+ Attempt to reduce a field access of a value of class type. */
+
+static tree
+eval_component_reference (const constexpr_ctx *ctx, tree t, bool lval,
+ bool *non_constant_p, bool *overflow_p)
+{
+ unsigned HOST_WIDE_INT i;
+ tree field;
+ tree value;
+ tree part = TREE_OPERAND (t, 1);
+ tree orig_whole = TREE_OPERAND (t, 0);
+ tree whole = eval_constant_expression (ctx, orig_whole, lval, non_constant_p,
+ overflow_p);
+ if (INDIRECT_REF_P (whole) && integer_zerop (TREE_OPERAND (whole, 0)))
+ {
+ if (!ctx->quiet)
+ error ("dereferencing a null pointer in %qE", orig_whole);
+ *non_constant_p = true;
+ return t;
+ }
+
+ if (whole == orig_whole)
+ return t;
+ if (lval)
+ return fold_build3 (COMPONENT_REF, TREE_TYPE (t), whole, part, NULL_TREE);
+ /* Don't VERIFY_CONSTANT here; we only want to check that we got a
+ CONSTRUCTOR. */
+ if (!*non_constant_p && TREE_CODE (whole) != CONSTRUCTOR)
+ {
+ if (!ctx->quiet)
+ error ("%qE is not a constant expression", orig_whole);
+ *non_constant_p = true;
+ }
+ if (DECL_MUTABLE_P (part))
+ {
+ if (!ctx->quiet)
+ error ("mutable %qD is not usable in a constant expression", part);
+ *non_constant_p = true;
+ }
+ if (*non_constant_p)
+ return t;
+ bool pmf = TYPE_PTRMEMFUNC_P (TREE_TYPE (whole));
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
+ {
+ /* Use name match for PMF fields, as a variant will have a
+ different FIELD_DECL with a different type. */
+ if (pmf ? DECL_NAME (field) == DECL_NAME (part) : field == part)
+ {
+ if (value)
+ {
+ STRIP_ANY_LOCATION_WRAPPER (value);
+ return value;
+ }
+ else
+ /* We're in the middle of initializing it. */
+ break;
+ }
+ }
+ if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE
+ && CONSTRUCTOR_NELTS (whole) > 0)
+ {
+ /* DR 1188 says we don't have to deal with this. */
+ if (!ctx->quiet)
+ {
+ constructor_elt *cep = CONSTRUCTOR_ELT (whole, 0);
+ if (cep->value == NULL_TREE)
+ error ("accessing uninitialized member %qD", part);
+ else
+ error ("accessing %qD member instead of initialized %qD member in "
+ "constant expression",
+ part, cep->index);
+ }
+ *non_constant_p = true;
+ return t;
+ }
+
+ /* We only create a CONSTRUCTOR for a subobject when we modify it, so empty
+ classes never get represented; throw together a value now. */
+ if (is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/ false))
+ return build_constructor (TREE_TYPE (t), NULL);
+
+ gcc_assert (DECL_CONTEXT (part) == TYPE_MAIN_VARIANT (TREE_TYPE (whole)));
+
+ if (CONSTRUCTOR_NO_CLEARING (whole))
+ {
+ /* 'whole' is part of the aggregate initializer we're currently
+ building; if there's no initializer for this member yet, that's an
+ error. */
+ if (!ctx->quiet)
+ error ("accessing uninitialized member %qD", part);
+ *non_constant_p = true;
+ return t;
+ }
+
+ /* If there's no explicit init for this field, it's value-initialized. */
+ // Faisal: commenting this out as not sure if we need this but we need to come
+ // back to handle this to assign suitable value to value before sending it in
+ // eval_constant_expression below
+ // value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
+ return eval_constant_expression (ctx, value, lval, non_constant_p,
+ overflow_p);
+}
+
static tree
eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
bool *non_constant_p, bool *overflow_p,
@@ -1964,6 +2231,24 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
eval_switch_expr (ctx, t, non_constant_p, overflow_p, jump_target);
break;
+ case ARRAY_REF:
+ r = eval_array_reference (ctx, t, lval, non_constant_p, overflow_p);
+ break;
+
+ case COMPONENT_REF:
+ if (is_overloaded_fn (t))
+ {
+ /* We can only get here in checking mode via
+ build_non_dependent_expr, because any expression that
+ calls or takes the address of the function will have
+ pulled a FUNCTION_DECL out of the COMPONENT_REF. */
+ gcc_checking_assert (ctx->quiet || errorcount);
+ *non_constant_p = true;
+ return t;
+ }
+ r = eval_component_reference (ctx, t, lval, non_constant_p, overflow_p);
+ break;
+
case BIT_FIELD_REF:
r = eval_bit_field_ref (ctx, t, lval, non_constant_p, overflow_p);
break;
@@ -4144,32 +4429,6 @@ extract_string_elt (tree string, unsigned chars_per_elt, unsigned index)
return r;
}
-// forked from gcc/cp/constexpr.cc free_constructor
-
-/* If T is a CONSTRUCTOR, ggc_free T and any sub-CONSTRUCTORs. */
-
-static void
-free_constructor (tree t)
-{
- if (!t || TREE_CODE (t) != CONSTRUCTOR)
- return;
- releasing_vec ctors;
- vec_safe_push (ctors, t);
- while (!ctors->is_empty ())
- {
- tree c = ctors->pop ();
- if (vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (c))
- {
- constructor_elt *ce;
- for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i)
- if (TREE_CODE (ce->value) == CONSTRUCTOR)
- vec_safe_push (ctors, ce->value);
- ggc_free (elts);
- }
- ggc_free (c);
- }
-}
-
/* Check whether the parameter and return types of FUN are valid for a
constexpr function, and complain if COMPLAIN. */
@@ -6129,6 +6388,22 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
&target);
}
+// forked from gcc/cp/constexpr.cc fold_non_dependent_init
+
+/* Like maybe_constant_init but first fully instantiate the argument. */
+
+tree
+fold_non_dependent_init (tree t,
+ tsubst_flags_t complain /*=tf_warning_or_error*/,
+ bool manifestly_const_eval /*=false*/,
+ tree object /* = NULL_TREE */)
+{
+ if (t == NULL_TREE)
+ return NULL_TREE;
+
+ return maybe_constant_init (t, object, manifestly_const_eval);
+}
+
// #include "gt-rust-rust-constexpr.h"
} // namespace Compile