public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] rust-constexpr.cc: port VIEW_CONVERT_EXPR and CONVERT_EXPR cases to eval_constant_expression(). Thro
@ 2022-08-29 15:34 Thomas Schwinge
0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-08-29 15:34 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:266891d17c751d104d8c75e0258cf1b462756ad9
commit 266891d17c751d104d8c75e0258cf1b462756ad9
Author: Faisal Abbas <90.abbasfaisal@gmail.com>
Date: Sat Jul 30 18:24:42 2022 +0100
rust-constexpr.cc: port VIEW_CONVERT_EXPR and CONVERT_EXPR cases to
eval_constant_expression(). Throws away code under UNARY_PLUS_EXPR
and PTRMEM_CST as those tree codes come from cp-tree.def.
Diff:
---
gcc/rust/backend/rust-constexpr.cc | 141 +++++++++++++++++++++++++++++++++++++
gcc/rust/backend/rust-tree.cc | 46 ++++++++++++
gcc/rust/backend/rust-tree.h | 17 +++++
3 files changed, 204 insertions(+)
diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index 1244047ef4f..ebd6ddec89d 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -574,6 +574,18 @@ fold_expr (tree expr)
return folded;
}
+static bool
+same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2)
+{
+ while (TREE_CODE (type1) == ARRAY_TYPE && TREE_CODE (type2) == ARRAY_TYPE
+ && (!TYPE_DOMAIN (type1) || !TYPE_DOMAIN (type2)))
+ {
+ type1 = TREE_TYPE (type1);
+ type2 = TREE_TYPE (type2);
+ }
+ return same_type_ignoring_top_level_qualifiers_p (type1, type2);
+}
+
static tree
eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
bool *non_constant_p, bool *overflow_p,
@@ -848,6 +860,135 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
jump_target);
break;
+ /* FALLTHROUGH. */
+ case CONVERT_EXPR:
+ case VIEW_CONVERT_EXPR: {
+ tree oldop = TREE_OPERAND (t, 0);
+
+ tree op = eval_constant_expression (ctx, oldop, lval, non_constant_p,
+ overflow_p);
+ if (*non_constant_p)
+ return t;
+ tree type = TREE_TYPE (t);
+
+ if (VOID_TYPE_P (type))
+ return void_node;
+
+ if (TREE_CODE (t) == CONVERT_EXPR && ARITHMETIC_TYPE_P (type)
+ && INDIRECT_TYPE_P (TREE_TYPE (op)) && ctx->manifestly_const_eval)
+ {
+ if (!ctx->quiet)
+ error_at (loc,
+ "conversion from pointer type %qT to arithmetic type "
+ "%qT in a constant expression",
+ TREE_TYPE (op), type);
+ *non_constant_p = true;
+ return t;
+ }
+
+ if (TYPE_PTROB_P (type) && TYPE_PTR_P (TREE_TYPE (op))
+ && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (op))))
+ {
+ /* Likewise, don't error when casting from void* when OP is
+ &heap uninit and similar. */
+ tree sop = tree_strip_nop_conversions (op);
+ if (TREE_CODE (sop) == ADDR_EXPR && VAR_P (TREE_OPERAND (sop, 0))
+ && DECL_ARTIFICIAL (TREE_OPERAND (sop, 0)))
+ /* OK */;
+ else
+ {
+ if (!ctx->quiet)
+ error_at (loc, "cast from %qT is not allowed",
+ TREE_TYPE (op));
+ *non_constant_p = true;
+ return t;
+ }
+ }
+
+ if (INDIRECT_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST)
+ {
+ if (integer_zerop (op))
+ {
+ if (TYPE_REF_P (type))
+ {
+ if (!ctx->quiet)
+ error_at (loc, "dereferencing a null pointer");
+ *non_constant_p = true;
+ return t;
+ }
+ }
+ else
+ {
+ /* This detects for example:
+ reinterpret_cast<void*>(sizeof 0)
+ */
+ if (!ctx->quiet)
+ error_at (loc,
+ "%<reinterpret_cast<%T>(%E)%> is not "
+ "a constant expression",
+ type, op);
+ *non_constant_p = true;
+ return t;
+ }
+ }
+
+ if (INDIRECT_TYPE_P (type) && TREE_CODE (op) == NOP_EXPR
+ && TREE_TYPE (op) == ptr_type_node
+ && TREE_CODE (TREE_OPERAND (op, 0)) == ADDR_EXPR
+ && VAR_P (TREE_OPERAND (TREE_OPERAND (op, 0), 0))
+ && (DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0), 0))
+ == heap_uninit_identifier
+ || DECL_NAME (TREE_OPERAND (TREE_OPERAND (op, 0), 0))
+ == heap_vec_uninit_identifier))
+ {
+ tree var = TREE_OPERAND (TREE_OPERAND (op, 0), 0);
+ tree var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+ tree elt_type = TREE_TYPE (type);
+ tree cookie_size = NULL_TREE;
+ if (TREE_CODE (elt_type) == RECORD_TYPE
+ && TYPE_NAME (elt_type) == heap_identifier)
+ {
+ tree fld1 = TYPE_FIELDS (elt_type);
+ tree fld2 = DECL_CHAIN (fld1);
+ elt_type = TREE_TYPE (TREE_TYPE (fld2));
+ cookie_size = TYPE_SIZE_UNIT (TREE_TYPE (fld1));
+ }
+ DECL_NAME (var) = (DECL_NAME (var) == heap_uninit_identifier
+ ? heap_identifier
+ : heap_vec_identifier);
+ TREE_TYPE (var)
+ = build_new_constexpr_heap_type (elt_type, cookie_size, var_size);
+ TREE_TYPE (TREE_OPERAND (op, 0))
+ = build_pointer_type (TREE_TYPE (var));
+ }
+
+ if (op == oldop)
+ /* We didn't fold at the top so we could check for ptr-int
+ conversion. */
+ return fold (t);
+
+ tree sop;
+
+ /* Handle an array's bounds having been deduced after we built
+ the wrapping expression. */
+ if (same_type_ignoring_tlq_and_bounds_p (type, TREE_TYPE (op)))
+ r = op;
+ else if (sop = tree_strip_nop_conversions (op),
+ sop != op
+ && (same_type_ignoring_tlq_and_bounds_p (type,
+ TREE_TYPE (sop))))
+ r = sop;
+ else
+ r = fold_build1 (tcode, type, op);
+
+ /* Conversion of an out-of-range value has implementation-defined
+ behavior; the language considers it different from arithmetic
+ overflow, which is undefined. */
+ if (TREE_OVERFLOW_P (r) && !TREE_OVERFLOW_P (op))
+ TREE_OVERFLOW (r) = false;
+ }
+ break;
+
default:
break;
}
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 98c112a7d83..82b58459d6f 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -4033,4 +4033,50 @@ location_of (tree t)
return EXPR_LOCATION (t);
}
+/* For element type ELT_TYPE, return the appropriate type of the heap object
+ containing such element(s). COOKIE_SIZE is NULL or the size of cookie
+ in bytes. FULL_SIZE is NULL if it is unknown how big the heap allocation
+ will be, otherwise size of the heap object. If COOKIE_SIZE is NULL,
+ return array type ELT_TYPE[FULL_SIZE / sizeof(ELT_TYPE)], otherwise return
+ struct { size_t[COOKIE_SIZE/sizeof(size_t)]; ELT_TYPE[N]; }
+ where N is nothing (flexible array member) if FULL_SIZE is NULL, otherwise
+ it is computed such that the size of the struct fits into FULL_SIZE. */
+
+tree
+build_new_constexpr_heap_type (tree elt_type, tree cookie_size, tree full_size)
+{
+ gcc_assert (cookie_size == NULL_TREE || tree_fits_uhwi_p (cookie_size));
+ gcc_assert (full_size == NULL_TREE || tree_fits_uhwi_p (full_size));
+ unsigned HOST_WIDE_INT csz = cookie_size ? tree_to_uhwi (cookie_size) : 0;
+ tree itype2 = NULL_TREE;
+ if (full_size)
+ {
+ unsigned HOST_WIDE_INT fsz = tree_to_uhwi (full_size);
+ gcc_assert (fsz >= csz);
+ fsz -= csz;
+ fsz /= int_size_in_bytes (elt_type);
+ itype2 = build_index_type (size_int (fsz - 1));
+ if (!cookie_size)
+ return build_cplus_array_type (elt_type, itype2);
+ }
+ else
+ gcc_assert (cookie_size);
+ csz /= int_size_in_bytes (sizetype);
+ tree itype1 = build_index_type (size_int (csz - 1));
+ tree atype1 = build_cplus_array_type (sizetype, itype1);
+ tree atype2 = build_cplus_array_type (elt_type, itype2);
+ tree rtype = cxx_make_type (RECORD_TYPE);
+ TYPE_NAME (rtype) = heap_identifier;
+ tree fld1 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype1);
+ tree fld2 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype2);
+ DECL_FIELD_CONTEXT (fld1) = rtype;
+ DECL_FIELD_CONTEXT (fld2) = rtype;
+ DECL_ARTIFICIAL (fld1) = true;
+ DECL_ARTIFICIAL (fld2) = true;
+ TYPE_FIELDS (rtype) = fld1;
+ DECL_CHAIN (fld1) = fld2;
+ layout_type (rtype);
+ return rtype;
+}
+
} // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index b7c4676f0ab..d4b7d8671fe 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -1248,6 +1248,21 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX];
are not constexprs. Other NOP_EXPRs are. */
#define REINTERPRET_CAST_P(NODE) TREE_LANG_FLAG_0 (NOP_EXPR_CHECK (NODE))
+/* Returns true if NODE is an object type:
+
+ [basic.types]
+
+ An object type is a (possibly cv-qualified) type that is not a
+ function type, not a reference type, and not a void type.
+
+ Keep these checks in ascending order, for speed. */
+#define TYPE_OBJ_P(NODE) \
+ (!TYPE_REF_P (NODE) && !VOID_TYPE_P (NODE) && !FUNC_OR_METHOD_TYPE_P (NODE))
+
+/* Returns true if NODE is a pointer to an object. Keep these checks
+ in ascending tree code order. */
+#define TYPE_PTROB_P(NODE) (TYPE_PTR_P (NODE) && TYPE_OBJ_P (TREE_TYPE (NODE)))
+
#if defined ENABLE_TREE_CHECKING
#define LANG_DECL_MIN_CHECK(NODE) \
@@ -2582,6 +2597,8 @@ extern bool require_deduced_type (tree, tsubst_flags_t = tf_warning_or_error);
extern bool decl_constant_var_p (tree);
+extern tree build_new_constexpr_heap_type (tree, tree, tree);
+
// forked from gcc/cp/cp-tree.h
enum
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-08-29 15:34 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:34 [gcc/devel/rust/master] rust-constexpr.cc: port VIEW_CONVERT_EXPR and CONVERT_EXPR cases to eval_constant_expression(). Thro 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).