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).