public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] rust-constexpr.cc: port over cxx_eval_array_reference and cxx_eval_component_reference.
@ 2022-08-29 15:35 Thomas Schwinge
0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-08-29 15:35 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:4ca228d2f32e5eb6e9516f487be85383225d5a00
commit 4ca228d2f32e5eb6e9516f487be85383225d5a00
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date: Tue Aug 16 12:40:33 2022 +0100
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.
Diff:
---
gcc/rust/backend/rust-constexpr.cc | 327 ++++++++++++++++++++++++++++++++++---
gcc/rust/backend/rust-tree.cc | 59 +++++++
gcc/rust/backend/rust-tree.h | 28 ++++
3 files changed, 388 insertions(+), 26 deletions(-)
diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index 5ac12d2ec6a..c0194db6b21 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
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index fc32c7c1c70..ce820f08eaa 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -6146,4 +6146,63 @@ explain_non_literal_class (tree t)
}
}
+// forked from gcc/cp/call.cc reference_related_p
+
+/* Returns nonzero if T1 is reference-related to T2. */
+
+bool
+reference_related_p (tree t1, tree t2)
+{
+ if (t1 == error_mark_node || t2 == error_mark_node)
+ return false;
+
+ t1 = TYPE_MAIN_VARIANT (t1);
+ t2 = TYPE_MAIN_VARIANT (t2);
+
+ /* [dcl.init.ref]
+
+ Given types "cv1 T1" and "cv2 T2," "cv1 T1" is reference-related
+ to "cv2 T2" if T1 is similar to T2, or T1 is a base class of T2. */
+ return (similar_type_p (t1, t2)
+ /*|| (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2)
+ && DERIVED_FROM_P (t1, t2))*/);
+}
+
+// forked from gcc/cp/typeck2.cc ordinary_char_type_p
+
+/* True iff TYPE is a C++20 "ordinary" character type. */
+
+bool
+ordinary_char_type_p (tree type)
+{
+ type = TYPE_MAIN_VARIANT (type);
+ return (type == char_type_node || type == signed_char_type_node
+ || type == unsigned_char_type_node);
+}
+
+// forked from gcc/cp/typeck2.cc array_string_literal_compatible_p
+
+/* True iff the string literal INIT has a type suitable for initializing array
+ TYPE. */
+
+bool
+array_string_literal_compatible_p (tree type, tree init)
+{
+ tree to_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ tree from_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+
+ if (to_char_type == from_char_type)
+ return true;
+ /* The array element type does not match the initializing string
+ literal element type; this is only allowed when both types are
+ ordinary character type. There are no string literals of
+ signed or unsigned char type in the language, but we can get
+ them internally from converting braced-init-lists to
+ STRING_CST. */
+ if (ordinary_char_type_p (to_char_type)
+ && ordinary_char_type_p (from_char_type))
+ return true;
+ return false;
+}
+
} // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 2466efc3309..87ed2b6ae56 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -1529,6 +1529,24 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
#define TYPE_HAS_COMPLEX_DFLT(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->has_complex_dflt)
+/* [dcl.init.aggr]
+
+ An aggregate is an array or a class with no user-provided
+ constructors, no brace-or-equal-initializers for non-static data
+ members, no private or protected non-static data members, no
+ base classes, and no virtual functions.
+
+ As an extension, we also treat vectors as aggregates. Keep these
+ checks in ascending code order. */
+#define CP_AGGREGATE_TYPE_P(TYPE) \
+ (gnu_vector_type_p (TYPE) || TREE_CODE (TYPE) == ARRAY_TYPE \
+ || (CLASS_TYPE_P (TYPE) && COMPLETE_TYPE_P (TYPE) \
+ && !CLASSTYPE_NON_AGGREGATE (TYPE)))
+
+/* Nonzero for a FIELD_DECL means that this member object type
+ is mutable. */
+#define DECL_MUTABLE_P(NODE) (DECL_LANG_FLAG_0 (FIELD_DECL_CHECK (NODE)))
+
#if defined ENABLE_TREE_CHECKING
#define LANG_DECL_MIN_CHECK(NODE) \
@@ -3116,6 +3134,12 @@ extern tree get_first_fn (tree) ATTRIBUTE_PURE;
extern void explain_non_literal_class (tree);
+extern bool reference_related_p (tree, tree);
+
+extern bool ordinary_char_type_p (tree);
+
+extern bool array_string_literal_compatible_p (tree, tree);
+
// forked from gcc/cp/cp-tree.h
enum
@@ -3351,6 +3375,10 @@ literal_type_p (tree t);
extern bool
maybe_constexpr_fn (tree t);
+
+extern tree
+fold_non_dependent_init (tree, tsubst_flags_t = tf_warning_or_error,
+ bool = false, tree = NULL_TREE);
}
} // namespace Rust
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-08-29 15:35 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-29 15:35 [gcc/devel/rust/master] rust-constexpr.cc: port over cxx_eval_array_reference and cxx_eval_component_reference Thomas Schwinge
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).