public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] gccrs const folding port: start porting cxx_eval_array_reference()
@ 2022-08-29 15:32 Thomas Schwinge
0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-08-29 15:32 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:7c13a2e5873f5919c00b5f37b6db52af8d0f7300
commit 7c13a2e5873f5919c00b5f37b6db52af8d0f7300
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date: Sat Jul 16 17:01:47 2022 +0100
gccrs const folding port: start porting cxx_eval_array_reference()
Following functions are ported in this changeset:
- array_index_cmp
- unshare_constructor
- find_array_ctor_elt
- reduced_constant_expression_p
- verify_constant
- diag_array_subscript
- get_array_or_vector_nelts
- eval_and_check_array_index
- extract_string_elt
- free_constructor
- cv_unqualified
- make_tree_vector
- release_tree_vector
- vec_safe_push
Following structs, classes and enums are ported in this changeset:
- releasing_vec
Signed-off-by: Faisal Abbas <90.abbasfaisal@gmail.com>
Diff:
---
gcc/rust/backend/rust-constexpr.cc | 549 +++++++++++++++++++++++++++++++++++--
gcc/rust/backend/rust-tree.cc | 68 +++++
gcc/rust/backend/rust-tree.h | 53 ++++
3 files changed, 653 insertions(+), 17 deletions(-)
diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index 53c6ef6a668..8fb378fbda5 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -25,10 +25,27 @@
#include "print-tree.h"
#include "gimplify.h"
#include "tree-iterator.h"
+#include "varasm.h"
+
+#define VERIFY_CONSTANT(X) \
+ do \
+ { \
+ if (verify_constant ((X), ctx->quiet, non_constant_p, overflow_p)) \
+ return t; \
+ } \
+ while (0)
namespace Rust {
namespace Compile {
+static bool
+verify_constant (tree, bool, bool *, bool *);
+
+static HOST_WIDE_INT
+find_array_ctor_elt (tree ary, tree dindex, bool insert = false);
+static int
+array_index_cmp (tree key, tree index);
+
struct constexpr_global_ctx
{
HOST_WIDE_INT constexpr_ops_count;
@@ -38,7 +55,19 @@ struct constexpr_global_ctx
struct constexpr_ctx
{
+ /* The part of the context that needs to be unique to the whole
+ cxx_eval_outermost_constant_expr invocation. */
constexpr_global_ctx *global;
+
+ /* Whether we should error on a non-constant expression or fail quietly.
+ This flag needs to be here, but some of the others could move to global
+ if they get larger than a word. */
+ bool quiet;
+ /* The object we're building the CONSTRUCTOR for. */
+ tree object;
+ /* The CONSTRUCTOR we're currently building up for an aggregate
+ initializer. */
+ tree ctor;
};
static tree
@@ -51,19 +80,20 @@ static void
non_const_var_error (location_t loc, tree r);
static tree
-constexpr_expression (const constexpr_ctx *ctx, tree);
+constexpr_expression (const constexpr_ctx *ctx, tree, bool, bool *, bool *,
+ tree * = NULL);
static tree
constexpr_fn_retval (const constexpr_ctx *ctx, tree r);
static tree
-eval_store_expression (const constexpr_ctx *ctx, tree r);
+eval_store_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *);
static tree
eval_call_expression (const constexpr_ctx *ctx, tree r);
static tree
-eval_binary_expression (const constexpr_ctx *ctx, tree r);
+eval_binary_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *);
static tree
get_function_named_in_call (tree t);
@@ -72,15 +102,20 @@ tree
fold_expr (tree expr)
{
constexpr_global_ctx global_ctx;
- constexpr_ctx ctx = {&global_ctx};
+ constexpr_ctx ctx = {&global_ctx, false};
+ bool non_constant_p = false;
+ bool overflow_p = false;
- tree folded = constexpr_expression (&ctx, expr);
+ tree folded
+ = constexpr_expression (&ctx, expr, false, &non_constant_p, &overflow_p);
rust_assert (folded != NULL_TREE);
return folded;
}
static tree
-constexpr_expression (const constexpr_ctx *ctx, tree t)
+constexpr_expression (const constexpr_ctx *ctx, tree t, bool lval,
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target /* = NULL */)
{
location_t loc = EXPR_LOCATION (t);
@@ -165,7 +200,7 @@ constexpr_expression (const constexpr_ctx *ctx, tree t)
case LTGT_EXPR:
case RANGE_EXPR:
case COMPLEX_EXPR:
- r = eval_binary_expression (ctx, t);
+ r = eval_binary_expression (ctx, t, false, non_constant_p, overflow_p);
break;
case CALL_EXPR:
@@ -174,11 +209,12 @@ constexpr_expression (const constexpr_ctx *ctx, tree t)
case RETURN_EXPR:
rust_assert (TREE_OPERAND (t, 0) != NULL_TREE);
- r = constexpr_expression (ctx, TREE_OPERAND (t, 0));
+ r = constexpr_expression (ctx, TREE_OPERAND (t, 0), false, non_constant_p,
+ overflow_p);
break;
case MODIFY_EXPR:
- r = eval_store_expression (ctx, t);
+ r = eval_store_expression (ctx, t, false, non_constant_p, overflow_p);
break;
default:
@@ -189,7 +225,8 @@ constexpr_expression (const constexpr_ctx *ctx, tree t)
}
static tree
-eval_store_expression (const constexpr_ctx *ctx, tree t)
+eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
+ bool *non_constant_p, bool *overflow_p)
{
tree init = TREE_OPERAND (t, 1);
if (TREE_CLOBBER_P (init))
@@ -219,7 +256,8 @@ eval_store_expression (const constexpr_ctx *ctx, tree t)
object = probe;
else
{
- probe = constexpr_expression (ctx, probe);
+ probe = constexpr_expression (ctx, probe, lval, non_constant_p,
+ overflow_p);
evaluated = true;
}
break;
@@ -232,14 +270,15 @@ eval_store_expression (const constexpr_ctx *ctx, tree t)
/* Subroutine of cxx_eval_constant_expression.
Like cxx_eval_unary_expression, except for binary expressions. */
static tree
-eval_binary_expression (const constexpr_ctx *ctx, tree t)
+eval_binary_expression (const constexpr_ctx *ctx, tree t, bool lval,
+ bool *non_constant_p, bool *overflow_p)
{
tree orig_lhs = TREE_OPERAND (t, 0);
tree orig_rhs = TREE_OPERAND (t, 1);
tree lhs, rhs;
- lhs = constexpr_expression (ctx, orig_lhs);
- rhs = constexpr_expression (ctx, orig_rhs);
+ lhs = constexpr_expression (ctx, orig_lhs, lval, non_constant_p, overflow_p);
+ rhs = constexpr_expression (ctx, orig_rhs, lval, non_constant_p, overflow_p);
location_t loc = EXPR_LOCATION (t);
enum tree_code code = TREE_CODE (t);
@@ -285,9 +324,12 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body)
return expr;
}
- case RETURN_EXPR:
- return constexpr_expression (ctx, body);
-
+ case RETURN_EXPR: {
+ bool non_constant_p = false;
+ bool overflow_p = false;
+ return constexpr_expression (ctx, body, false, &non_constant_p,
+ &overflow_p);
+ }
case DECL_EXPR: {
tree decl = DECL_EXPR_DECL (body);
if (TREE_CODE (decl) == USING_DECL
@@ -437,5 +479,478 @@ 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
+
+/* Returns less than, equal to, or greater than zero if KEY is found to be
+ less than, to match, or to be greater than the constructor_elt's INDEX. */
+
+static int
+array_index_cmp (tree key, tree index)
+{
+ gcc_assert (TREE_CODE (key) == INTEGER_CST);
+
+ switch (TREE_CODE (index))
+ {
+ case INTEGER_CST:
+ return tree_int_cst_compare (key, index);
+ case RANGE_EXPR: {
+ tree lo = TREE_OPERAND (index, 0);
+ tree hi = TREE_OPERAND (index, 1);
+ if (tree_int_cst_lt (key, lo))
+ return -1;
+ else if (tree_int_cst_lt (hi, key))
+ return 1;
+ else
+ return 0;
+ }
+ default:
+ gcc_unreachable ();
+ }
+}
+
+// forked from gcc/cp/constexpr.cc unshare_constructor
+
+/* If T is a CONSTRUCTOR, return an unshared copy of T and any
+ sub-CONSTRUCTORs. Otherwise return T.
+
+ We use this whenever we initialize an object as a whole, whether it's a
+ parameter, a local variable, or a subobject, so that subsequent
+ modifications don't affect other places where it was used. */
+
+tree
+unshare_constructor (tree t MEM_STAT_DECL)
+{
+ if (!t || TREE_CODE (t) != CONSTRUCTOR)
+ return t;
+ auto_vec<tree *, 4> ptrs;
+ ptrs.safe_push (&t);
+ while (!ptrs.is_empty ())
+ {
+ tree *p = ptrs.pop ();
+ tree n = copy_node (*p PASS_MEM_STAT);
+ CONSTRUCTOR_ELTS (n)
+ = vec_safe_copy (CONSTRUCTOR_ELTS (*p) PASS_MEM_STAT);
+ *p = n;
+ vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (n);
+ constructor_elt *ce;
+ for (HOST_WIDE_INT i = 0; vec_safe_iterate (v, i, &ce); ++i)
+ if (ce->value && TREE_CODE (ce->value) == CONSTRUCTOR)
+ ptrs.safe_push (&ce->value);
+ }
+ return t;
+}
+
+// forked from gcc/cp/constexpr.cc find_array_ctor_elt
+
+/* Returns the index of the constructor_elt of ARY which matches DINDEX, or -1
+ if none. If INSERT is true, insert a matching element rather than fail. */
+
+static HOST_WIDE_INT
+find_array_ctor_elt (tree ary, tree dindex, bool insert)
+{
+ if (tree_int_cst_sgn (dindex) < 0)
+ return -1;
+
+ unsigned HOST_WIDE_INT i = tree_to_uhwi (dindex);
+ vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ary);
+ unsigned HOST_WIDE_INT len = vec_safe_length (elts);
+
+ unsigned HOST_WIDE_INT end = len;
+ unsigned HOST_WIDE_INT begin = 0;
+
+ /* If the last element of the CONSTRUCTOR has its own index, we can assume
+ that the same is true of the other elements and index directly. */
+ if (end > 0)
+ {
+ tree cindex = (*elts)[end - 1].index;
+ if (cindex == NULL_TREE)
+ {
+ /* Verify that if the last index is missing, all indexes
+ are missing. */
+ if (flag_checking)
+ for (unsigned int j = 0; j < len - 1; ++j)
+ gcc_assert ((*elts)[j].index == NULL_TREE);
+ if (i < end)
+ return i;
+ else
+ {
+ begin = end;
+ if (i == end)
+ /* If the element is to be added right at the end,
+ make sure it is added with cleared index too. */
+ dindex = NULL_TREE;
+ else if (insert)
+ /* Otherwise, in order not to break the assumption
+ that CONSTRUCTOR either has all indexes or none,
+ we need to add indexes to all elements. */
+ for (unsigned int j = 0; j < len; ++j)
+ (*elts)[j].index = build_int_cst (TREE_TYPE (dindex), j);
+ }
+ }
+ else if (TREE_CODE (cindex) == INTEGER_CST
+ && compare_tree_int (cindex, end - 1) == 0)
+ {
+ if (i < end)
+ return i;
+ else
+ begin = end;
+ }
+ }
+
+ /* Otherwise, find a matching index by means of a binary search. */
+ while (begin != end)
+ {
+ unsigned HOST_WIDE_INT middle = (begin + end) / 2;
+ constructor_elt &elt = (*elts)[middle];
+ tree idx = elt.index;
+
+ int cmp = array_index_cmp (dindex, idx);
+ if (cmp < 0)
+ end = middle;
+ else if (cmp > 0)
+ begin = middle + 1;
+ else
+ {
+ if (insert && TREE_CODE (idx) == RANGE_EXPR)
+ {
+ /* We need to split the range. */
+ constructor_elt e;
+ tree lo = TREE_OPERAND (idx, 0);
+ tree hi = TREE_OPERAND (idx, 1);
+ tree value = elt.value;
+ dindex = fold_convert (sizetype, dindex);
+ if (tree_int_cst_lt (lo, dindex))
+ {
+ /* There are still some lower elts; shorten the range. */
+ tree new_hi
+ = int_const_binop (MINUS_EXPR, dindex, size_one_node);
+ if (tree_int_cst_equal (lo, new_hi))
+ /* Only one element left, no longer a range. */
+ elt.index = lo;
+ else
+ TREE_OPERAND (idx, 1) = new_hi;
+ /* Append the element we want to insert. */
+ ++middle;
+ e.index = dindex;
+ e.value = unshare_constructor (value);
+ vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle, e);
+ }
+ else
+ /* No lower elts, the range elt is now ours. */
+ elt.index = dindex;
+
+ if (tree_int_cst_lt (dindex, hi))
+ {
+ /* There are still some higher elts; append a range. */
+ tree new_lo
+ = int_const_binop (PLUS_EXPR, dindex, size_one_node);
+ if (tree_int_cst_equal (new_lo, hi))
+ e.index = hi;
+ else
+ e.index = build2 (RANGE_EXPR, sizetype, new_lo, hi);
+ e.value = unshare_constructor (value);
+ vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle + 1, e);
+ }
+ }
+ return middle;
+ }
+ }
+
+ if (insert)
+ {
+ constructor_elt e = {dindex, NULL_TREE};
+ vec_safe_insert (CONSTRUCTOR_ELTS (ary), end, e);
+ return end;
+ }
+
+ return -1;
+}
+
+// forked from gcc/cp/constexpr.cc reduced_constant_expression_p
+
+/* 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;
+ }
+}
+
+// forked from gcc/cp/constexpr.cc verify_constant
+
+/* Some expressions may have constant operands but are not constant
+ themselves, such as 1/0. Call this function to check for that
+ condition.
+
+ We only call this in places that require an arithmetic constant, not in
+ places where we might have a non-constant expression that can be a
+ component of a constant expression, such as the address of a constexpr
+ variable that might be dereferenced later. */
+
+static bool
+verify_constant (tree t, bool allow_non_constant, bool *non_constant_p,
+ bool *overflow_p)
+{
+ if (!*non_constant_p && !reduced_constant_expression_p (t) && t != void_node)
+ {
+ if (!allow_non_constant)
+ error ("%q+E is not a constant expression", t);
+ *non_constant_p = true;
+ }
+ if (TREE_OVERFLOW_P (t))
+ {
+ if (!allow_non_constant)
+ {
+ permerror (input_location, "overflow in constant expression");
+ /* If we're being permissive (and are in an enforcing
+ context), ignore the overflow. */
+ if (flag_permissive)
+ return *non_constant_p;
+ }
+ *overflow_p = true;
+ }
+ return *non_constant_p;
+}
+
+// forked in gcc/cp/constexpr.cc diag_array_subscript
+
+/* Under the control of CTX, issue a detailed diagnostic for
+ an out-of-bounds subscript INDEX into the expression ARRAY. */
+
+static void
+diag_array_subscript (location_t loc, const constexpr_ctx *ctx, tree array,
+ tree index)
+{
+ if (!ctx->quiet)
+ {
+ tree arraytype = TREE_TYPE (array);
+
+ /* Convert the unsigned array subscript to a signed integer to avoid
+ printing huge numbers for small negative values. */
+ tree sidx = fold_convert (ssizetype, index);
+ STRIP_ANY_LOCATION_WRAPPER (array);
+ if (DECL_P (array))
+ {
+ if (TYPE_DOMAIN (arraytype))
+ error_at (loc,
+ "array subscript value %qE is outside the bounds "
+ "of array %qD of type %qT",
+ sidx, array, arraytype);
+ else
+ error_at (loc,
+ "nonzero array subscript %qE is used with array %qD of "
+ "type %qT with unknown bounds",
+ sidx, array, arraytype);
+ inform (DECL_SOURCE_LOCATION (array), "declared here");
+ }
+ else if (TYPE_DOMAIN (arraytype))
+ error_at (loc,
+ "array subscript value %qE is outside the bounds "
+ "of array type %qT",
+ sidx, arraytype);
+ else
+ error_at (loc,
+ "nonzero array subscript %qE is used with array of type %qT "
+ "with unknown bounds",
+ sidx, arraytype);
+ }
+}
+
+// forked from gcc/cp/constexpr.cc get_array_or_vector_nelts
+
+/* Return the number of elements for TYPE (which is an ARRAY_TYPE or
+ a VECTOR_TYPE). */
+
+static tree
+get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, bool *overflow_p)
+{
+ tree nelts;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (TYPE_DOMAIN (type))
+ nelts = array_type_nelts_top (type);
+ else
+ nelts = size_zero_node;
+ }
+ else if (VECTOR_TYPE_P (type))
+ nelts = size_int (TYPE_VECTOR_SUBPARTS (type));
+ else
+ gcc_unreachable ();
+
+ /* For VLAs, the number of elements won't be an integer constant. */
+ nelts = constexpr_expression (ctx, nelts, false, non_constant_p, overflow_p);
+ return nelts;
+}
+
+// forked from gcc/cp/constexpr.cc eval_and_check_array_index
+
+/* Subroutine of cxx_eval_array_reference. T is an ARRAY_REF; evaluate the
+ subscript, diagnose any problems with it, and return the result. */
+
+static tree
+eval_and_check_array_index (const constexpr_ctx *ctx, tree t,
+ bool allow_one_past, bool *non_constant_p,
+ bool *overflow_p)
+{
+ location_t loc = rs_expr_loc_or_input_loc (t);
+ tree ary = TREE_OPERAND (t, 0);
+ t = TREE_OPERAND (t, 1);
+ tree index
+ = constexpr_expression (ctx, t, allow_one_past, non_constant_p, overflow_p);
+ VERIFY_CONSTANT (index);
+
+ if (!tree_fits_shwi_p (index) || tree_int_cst_sgn (index) < 0)
+ {
+ diag_array_subscript (loc, ctx, ary, index);
+ *non_constant_p = true;
+ return t;
+ }
+
+ tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
+ overflow_p);
+ VERIFY_CONSTANT (nelts);
+ if (allow_one_past ? !tree_int_cst_le (index, nelts)
+ : !tree_int_cst_lt (index, nelts))
+ {
+ diag_array_subscript (loc, ctx, ary, index);
+ *non_constant_p = true;
+ return t;
+ }
+
+ return index;
+}
+
+// forked from gcc/cp/constexpr.cc extract_string_elt
+
+/* Extract element INDEX consisting of CHARS_PER_ELT chars from
+ STRING_CST STRING. */
+
+static tree
+extract_string_elt (tree string, unsigned chars_per_elt, unsigned index)
+{
+ tree type = cv_unqualified (TREE_TYPE (TREE_TYPE (string)));
+ tree r;
+
+ if (chars_per_elt == 1)
+ r = build_int_cst (type, TREE_STRING_POINTER (string)[index]);
+ else
+ {
+ const unsigned char *ptr
+ = ((const unsigned char *) TREE_STRING_POINTER (string)
+ + index * chars_per_elt);
+ r = native_interpret_expr (type, ptr, chars_per_elt);
+ }
+ 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);
+ }
+}
+
} // namespace Compile
} // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 52dae395973..9221f7bb081 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -3154,4 +3154,72 @@ check_for_uninitialized_const_var (tree decl, bool constexpr_context_p,
return true;
}
+
+// forked from gcc/cp/tree.cc cv_unqualified
+
+/* Return TYPE with const and volatile removed. */
+
+tree
+cv_unqualified (tree type)
+{
+ int quals;
+
+ if (type == error_mark_node)
+ return type;
+
+ quals = rs_type_quals (type);
+ quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+ return rs_build_qualified_type (type, quals);
+}
+
+/* The C and C++ parsers both use vectors to hold function arguments.
+ For efficiency, we keep a cache of unused vectors. This is the
+ cache. */
+
+typedef vec<tree, va_gc> *tree_gc_vec;
+static GTY ((deletable)) vec<tree_gc_vec, va_gc> *tree_vector_cache;
+
+// forked from gcc/c-family/c-common.c make_tree_vector
+
+/* Return a new vector from the cache. If the cache is empty,
+ allocate a new vector. These vectors are GC'ed, so it is OK if the
+ pointer is not released.. */
+
+vec<tree, va_gc> *
+make_tree_vector (void)
+{
+ if (tree_vector_cache && !tree_vector_cache->is_empty ())
+ return tree_vector_cache->pop ();
+ else
+ {
+ /* Passing 0 to vec::alloc returns NULL, and our callers require
+ that we always return a non-NULL value. The vector code uses
+ 4 when growing a NULL vector, so we do too. */
+ vec<tree, va_gc> *v;
+ vec_alloc (v, 4);
+ return v;
+ }
+}
+
+// forked from gcc/c-family/c-common.c release_tree_vector
+
+/* Release a vector of trees back to the cache. */
+
+void
+release_tree_vector (vec<tree, va_gc> *vec)
+{
+ if (vec != NULL)
+ {
+ if (vec->allocated () >= 16)
+ /* Don't cache vecs that have expanded more than once. On a p64
+ target, vecs double in alloc size with each power of 2 elements, e.g
+ at 16 elements the alloc increases from 128 to 256 bytes. */
+ vec_free (vec);
+ else
+ {
+ vec->truncate (0);
+ vec_safe_push (tree_vector_cache, vec);
+ }
+ }
+}
} // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index b838e402c32..b93e9364990 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2009,6 +2009,59 @@ gnu_vector_type_p (const_tree type)
return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type);
}
+extern vec<tree, va_gc> *
+make_tree_vector (void);
+
+extern void
+release_tree_vector (vec<tree, va_gc> *);
+
+/* Simplified unique_ptr clone to release a tree vec on exit. */
+
+class releasing_vec
+{
+public:
+ typedef vec<tree, va_gc> vec_t;
+
+ releasing_vec (vec_t *v) : v (v) {}
+ releasing_vec () : v (make_tree_vector ()) {}
+
+ /* Copy ops are deliberately declared but not defined,
+ copies must always be elided. */
+ releasing_vec (const releasing_vec &);
+ releasing_vec &operator= (const releasing_vec &);
+
+ vec_t &operator* () const { return *v; }
+ vec_t *operator-> () const { return v; }
+ vec_t *get () const { return v; }
+ operator vec_t * () const { return v; }
+ vec_t **operator& () { return &v; }
+
+ /* Breaks pointer/value consistency for convenience. This takes ptrdiff_t
+ rather than unsigned to avoid ambiguity with the built-in operator[]
+ (bootstrap/91828). */
+ tree &operator[] (ptrdiff_t i) const { return (*v)[i]; }
+
+ tree *begin () { return ::begin (v); }
+ tree *end () { return ::end (v); }
+
+ void release ()
+ {
+ release_tree_vector (v);
+ v = NULL;
+ }
+
+ ~releasing_vec () { release_tree_vector (v); }
+
+private:
+ vec_t *v;
+};
+
+inline tree *
+vec_safe_push (releasing_vec &r, const tree &t CXX_MEM_STAT_INFO)
+{
+ return vec_safe_push (*&r, t PASS_MEM_STAT);
+}
+
} // namespace Rust
#endif // RUST_TREE
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-08-29 15:32 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:32 [gcc/devel/rust/master] gccrs const folding port: start porting cxx_eval_array_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).