From: Enes Cevik <[email protected]>

This patch adds the 'assert_zero_valid' intrinsic to the compiler.
Properly implementing this intrinsic requires layout engine support to
detect types that cannot be safely zero-initialized (e.g., references
and NonNull types). Since gccrs currently lacks this capability, it is
implemented as a temporary stub that always returns unit `()`.

Normally, this intrinsic should inject a runtime panic during codegen
if the provided type does not permit zero-initialization.

gcc/rust/ChangeLog:

        * backend/rust-compile-intrinsic.cc (generic_intrinsics): Add
        assert_zero_valid to map.
        * backend/rust-intrinsic-handlers.cc
        (assert_zero_valid_handler): New function.
        * backend/rust-intrinsic-handlers.h (assert_zero_valid_handler):
        New declaration.
        * typecheck/rust-hir-type-check-intrinsic.cc
        (IntrinsicChecker::intrinsic_rules): Add new signature rule for
        assert_zero_valid.
        * util/rust-intrinsic-values.h (class Intrinsics): Add
        ASSERT_ZERO_VALID constexpr.

gcc/testsuite/ChangeLog:

        * rust/compile/assert_zero_valid.rs: New test.

Signed-off-by: Enes Cevik <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/064dddd85984adb7d47ad2d552d70c1295fcdbe8

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4697

 gcc/rust/backend/rust-compile-intrinsic.cc    |  1 +
 gcc/rust/backend/rust-intrinsic-handlers.cc   | 51 +++++++++++++++++++
 gcc/rust/backend/rust-intrinsic-handlers.h    |  2 +
 .../rust-hir-type-check-intrinsic.cc          |  3 +-
 gcc/rust/util/rust-intrinsic-values.h         |  1 +
 .../rust/compile/assert_zero_valid.rs         | 16 ++++++
 6 files changed, 73 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/rust/compile/assert_zero_valid.rs

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 205bf4113..b48647670 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -31,6 +31,7 @@ static const std::map<std::string, handlers::HandlerBuilder> 
generic_intrinsics
   = {{IValue::OFFSET, handlers::offset},
      {IValue::ARITH_OFFSET, handlers::arith_offset_handler},
      {IValue::WRITE_BYTES, handlers::write_bytes_handler},
+     {IValue::ASSERT_ZERO_VALID, handlers::assert_zero_valid_handler},
      {IValue::SIZE_OF, handlers::sizeof_handler},
      {IValue::SIZE_OF_VAL, handlers::size_of_val_handler},
      {IValue::MIN_ALIGN_OF, handlers::min_align_of_handler},
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc 
b/gcc/rust/backend/rust-intrinsic-handlers.cc
index b119593b8..6069898da 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -2176,6 +2176,57 @@ arith_offset_handler (Context *ctx, TyTy::FnType 
*fntype, location_t expr_locus)
   return fndecl;
 }
 
+/**
+ * pub fn assert_zero_valid<T>();
+ *
+ * TODO: Since gccrs currently lacks comprehensive layout engine support for
+ * validity ranges (such as `rustc_layout_scalar_valid_range_start`), we cannot
+ * accurately determine if a type is safely zeroable. Therefore, this is
+ * implemented as a temporary no-op stub that always returns void (unit) and
+ * succeeds for all types.
+ */
+tree
+assert_zero_valid_handler (Context *ctx, TyTy::FnType *fntype, location_t)
+{
+  rust_assert (fntype->get_params ().size () == 0);
+
+  tree lookup = NULL_TREE;
+  if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+    return lookup;
+
+  auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+  rust_assert (fntype->get_num_substitutions () == 1);
+  auto &param_mapping = fntype->get_substs ().at (0);
+  const auto param_tyty = param_mapping.get_param_ty ();
+  auto resolved_tyty = param_tyty->resolve ();
+
+  // Safely resolve the template parameter type to ensure monomorphization
+  // works.
+  // Suppress unused-variable warning since layout verification is a FIXME.
+  [[gnu::unused]] tree template_parameter_type
+    = TyTyResolveCompile::compile (ctx, resolved_tyty);
+
+  enter_intrinsic_block (ctx, fndecl);
+
+  // BUILTIN assert_zero_valid FN BODY BEGIN
+
+  // TODO: Implement layout verification via template_parameter_type once
+  // niche-filling and valid scalar ranges are supported in the layout engine.
+  // If invalid, this should emit a panic.
+
+  // we always return unit for now.
+  auto return_statement
+    = Backend::return_statement (fndecl, void_node, UNDEF_LOCATION);
+  ctx->add_statement (return_statement);
+
+  // BUILTIN assert_zero_valid FN BODY END
+
+  finalize_intrinsic_block (ctx, fndecl);
+
+  return fndecl;
+}
+
 } // namespace handlers
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h 
b/gcc/rust/backend/rust-intrinsic-handlers.h
index 8916c59f3..712d422e5 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -104,6 +104,8 @@ tree write_bytes_handler (Context *ctx, TyTy::FnType 
*fntype,
                          location_t expr_locus);
 tree arith_offset_handler (Context *ctx, TyTy::FnType *fntype,
                           location_t expr_locus);
+tree assert_zero_valid_handler (Context *ctx, TyTy::FnType *fntype,
+                               location_t expr_locus);
 
 } // namespace handlers
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc 
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index df596c58a..a0a047963 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -311,7 +311,8 @@ const std::unordered_map<std::string, IntrinsicRules>
     // fn write_bytes<T>(dst: *mut T, val: u8, count: usize)
     {IValue::WRITE_BYTES,
      {1, {IRT::MutPtrFirstGeneric, IRT::U8, IRT::Usize}, IRT::Unit}},
-
+    // pub fn assert_zero_valid<T>();
+    {IValue::ASSERT_ZERO_VALID, {1, {}, IRT::Unit}},
 };
 
 IntrinsicCheckResult
diff --git a/gcc/rust/util/rust-intrinsic-values.h 
b/gcc/rust/util/rust-intrinsic-values.h
index d79326459..f6e36a386 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -161,6 +161,7 @@ public:
   static constexpr auto &BLACK_BOX = "black_box";
   static constexpr auto &ARITH_OFFSET = "arith_offset";
   static constexpr auto &WRITE_BYTES = "write_bytes";
+  static constexpr auto &ASSERT_ZERO_VALID = "assert_zero_valid";
 };
 } // namespace Values
 } // namespace Rust
diff --git a/gcc/testsuite/rust/compile/assert_zero_valid.rs 
b/gcc/testsuite/rust/compile/assert_zero_valid.rs
new file mode 100644
index 000000000..afcb11e37
--- /dev/null
+++ b/gcc/testsuite/rust/compile/assert_zero_valid.rs
@@ -0,0 +1,16 @@
+#![feature(intrinsics, no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+extern "rust-intrinsic" {
+    fn assert_zero_valid<T>();
+}
+
+fn main() {
+    unsafe {
+        assert_zero_valid::<i32>();
+        assert_zero_valid::<&i32>();
+    }
+}

base-commit: 7cc595fafff3bafc115127818a0b890194ff84c0
-- 
2.54.0

Reply via email to