[gcc r17-2255] gccrs: intrinsic: Add size_of_val

Arthur Cohen via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:46d2b1f7b898c309bd2d61200a91bfd4c285c8ca

commit r17-2255-g46d2b1f7b898c309bd2d61200a91bfd4c285c8ca
Author: Enes Cevik <[email protected]>
Date:   Mon Jun 29 16:03:44 2026 +0300

    gccrs: intrinsic: Add size_of_val
    
    This patch adds the size_of_val intrinsic to the compiler. This
    intrinsic evaluates the size of a value at runtime, including
    Dynamically Sized Types (DSTs).
    
    gcc/rust/ChangeLog:
    
            * backend/rust-compile-intrinsic.cc (generic_intrinsics): Add
            size_of_val_handler to the map.
            * backend/rust-intrinsic-handlers.cc (size_of_val_handler): New
            function.
            * backend/rust-intrinsic-handlers.h (size_of_val_handler): New
            declaration.
            * typecheck/rust-hir-type-check-intrinsic.cc
            (IntrinsicChecker::intrinsic_rules): Add size_of_val signature
            rule to the map.
            * util/rust-intrinsic-values.h (class Intrinsics): Add
            SIZE_OF_VAL constexpr.
    
    gcc/testsuite/ChangeLog:
    
            * rust/execute/size-of-val.rs: New test.
    
    Signed-off-by: Enes Cevik <[email protected]>

Diff:
---
 gcc/rust/backend/rust-compile-intrinsic.cc         |   1 +
 gcc/rust/backend/rust-intrinsic-handlers.cc        | 102 +++++++++++++++++++++
 gcc/rust/backend/rust-intrinsic-handlers.h         |   2 +
 .../typecheck/rust-hir-type-check-intrinsic.cc     |   2 +
 gcc/rust/util/rust-intrinsic-values.h              |   1 +
 gcc/testsuite/rust/execute/size-of-val.rs          |  63 +++++++++++++
 6 files changed, 171 insertions(+)

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc
index e9407e051115..05187c35ca4b 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -32,6 +32,7 @@ static const std::map<std::string, handlers::HandlerBuilder> generic_intrinsics
      {IValue::ARITH_OFFSET, handlers::arith_offset_handler},
      {IValue::WRITE_BYTES, handlers::write_bytes_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},
      {IValue::TRANSMUTE, handlers::transmute},
      {IValue::ROTATE_LEFT, handlers::rotate_left},
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc b/gcc/rust/backend/rust-intrinsic-handlers.cc
index 735529cc947a..d08b1e2e2d61 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -1609,6 +1609,108 @@ sizeof_handler (Context *ctx, TyTy::FnType *fntype, location_t)
   return fndecl;
 }
 
+/**
+ * pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
+ */
+tree
+size_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
+{
+  rust_assert (fntype->get_params ().size () == 1);
+
+  tree lookup = NULL_TREE;
+  if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+    return lookup;
+
+  auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+  auto locus = fntype->get_locus ();
+
+  std::vector<Bvariable *> param_vars;
+  compile_fn_params (ctx, fntype, fndecl, &param_vars);
+
+  auto &__param = param_vars.at (0);
+  rust_assert (param_vars.size () == 1);
+  if (!Backend::function_set_parameters (fndecl, param_vars))
+    return error_mark_node;
+
+  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 ();
+  tree template_parameter_type
+    = TyTyResolveCompile::compile (ctx, resolved_tyty);
+
+  enter_intrinsic_block (ctx, fndecl);
+
+  // BUILTIN size_of FN BODY BEGIN
+
+  tree size_expr = NULL_TREE;
+  if (RS_DST_FLAG_P (template_parameter_type))
+    {
+      tree param = Backend::var_expression (__param, UNDEF_LOCATION);
+      tree param_ty = TREE_TYPE (param);
+      tree data_field = TYPE_FIELDS (param_ty);
+      tree meta_field = DECL_CHAIN (data_field);
+      tree meta_field_expr
+	= build3_loc (locus, COMPONENT_REF, TREE_TYPE (meta_field), param,
+		      meta_field, NULL_TREE);
+
+      if (resolved_tyty->get_kind () == TyTy::TypeKind::SLICE
+	  || resolved_tyty->get_kind () == TyTy::TypeKind::STR)
+	{
+	  tree elem_type = NULL_TREE;
+	  if (resolved_tyty->get_kind () == TyTy::TypeKind::SLICE)
+	    {
+	      auto slice_tyty = static_cast<TyTy::SliceType *> (resolved_tyty);
+	      elem_type
+		= TyTyResolveCompile::compile (ctx,
+					       slice_tyty->get_element_type ());
+	    }
+	  else
+	    elem_type = char_type_node;
+
+	  tree elem_size = TYPE_SIZE_UNIT (elem_type);
+	  size_expr
+	    = build2_loc (locus, MULT_EXPR, size_type_node,
+			  fold_convert_loc (locus, size_type_node,
+					    meta_field_expr),
+			  fold_convert_loc (locus, size_type_node, elem_size));
+	}
+      else if (resolved_tyty->get_kind () == TyTy::TypeKind::DYNAMIC)
+	{
+	  tree vtable_ptr_ty = TREE_TYPE (meta_field_expr);
+	  tree vtable_ty = TREE_TYPE (vtable_ptr_ty);
+
+	  tree vtable_ref
+	    = build1_loc (locus, INDIRECT_REF, vtable_ty, meta_field_expr);
+
+	  tree vtable_field_0 = TYPE_FIELDS (vtable_ty);
+	  tree vtable_field_size = DECL_CHAIN (vtable_field_0);
+	  rust_assert (vtable_field_size != NULL_TREE);
+
+	  size_expr
+	    = build3_loc (locus, COMPONENT_REF, TREE_TYPE (vtable_field_size),
+			  vtable_ref, vtable_field_size, NULL_TREE);
+	}
+      else
+	{
+	  rust_unreachable ();
+	}
+    }
+  else
+    size_expr = TYPE_SIZE_UNIT (template_parameter_type);
+
+  auto return_statement
+    = Backend::return_statement (fndecl, size_expr, UNDEF_LOCATION);
+  ctx->add_statement (return_statement);
+
+  // BUILTIN size_of FN BODY END
+
+  finalize_intrinsic_block (ctx, fndecl);
+
+  return fndecl;
+}
+
 /**
  * pub fn min_align_of<T>() -> usize;
  */
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h b/gcc/rust/backend/rust-intrinsic-handlers.h
index 1c81417b7024..58f52650a451 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -58,6 +58,8 @@ tree rotate_right (Context *ctx, TyTy::FnType *fntype, location_t expr_locus);
 const HandlerBuilder wrapping_op (tree_code op);
 tree offset (Context *ctx, TyTy::FnType *fntype, location_t expr_locus);
 tree sizeof_handler (Context *ctx, TyTy::FnType *fntype, location_t expr_locus);
+tree size_of_val_handler (Context *ctx, TyTy::FnType *fntype,
+			  location_t expr_locus);
 tree min_align_of_handler (Context *ctx, TyTy::FnType *fntype,
 			   location_t expr_locus);
 tree transmute (Context *ctx, TyTy::FnType *fntype, location_t expr_locus);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index 0011e3203d52..bfb5baf3161a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -128,6 +128,8 @@ const std::unordered_map<std::string, IntrinsicRules>
      {1, {IRT::ConstPtrFirstGeneric, IRT::Isize}, IRT::ConstPtrFirstGeneric}},
     // pub fn size_of<T>() -> usize;
     {IValue::SIZE_OF, {1, {}, IRT::Usize}},
+    // pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
+    {IValue::SIZE_OF_VAL, {1, {IRT::ConstPtrFirstGeneric}, IRT::Usize}},
     // pub fn transmute<T, U>(e: T) -> U;
     {IValue::TRANSMUTE, {2, {IRT::FirstGeneric}, IRT::SecondGeneric}},
     // pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
diff --git a/gcc/rust/util/rust-intrinsic-values.h b/gcc/rust/util/rust-intrinsic-values.h
index d47e66ce6e9f..35e76a87c349 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -84,6 +84,7 @@ public:
   static constexpr auto &ABORT = "abort";
   static constexpr auto &OFFSET = "offset";
   static constexpr auto &SIZE_OF = "size_of";
+  static constexpr auto &SIZE_OF_VAL = "size_of_val";
   static constexpr auto &TRANSMUTE = "transmute";
 
   static constexpr auto &ADD_WITH_OVERFLOW = "add_with_overflow";
diff --git a/gcc/testsuite/rust/execute/size-of-val.rs b/gcc/testsuite/rust/execute/size-of-val.rs
new file mode 100644
index 000000000000..5fb9407e611c
--- /dev/null
+++ b/gcc/testsuite/rust/execute/size-of-val.rs
@@ -0,0 +1,63 @@
+#![feature(no_core, intrinsics, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+extern "rust-intrinsic" {
+    pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
+}
+
+trait TraitA {
+    fn foo(&self) {}
+}
+
+struct StructA {
+    _a: i32,
+    _b: i32,
+}
+
+impl TraitA for StructA {}
+impl TraitA for u8 {}
+
+fn main() -> i32 {
+    let val_i32: i32 = 32;
+    let size_i32 = unsafe { size_of_val(&val_i32 as *const i32) };
+
+    let val_struct = StructA { _a: 1, _b: 2 };
+    let size_struct = unsafe { size_of_val(&val_struct as *const StructA) };
+
+    let arr: [i32; 3] = [10, 20, 30];
+    let val_slice: &[i32] = &arr;
+    let size_slice = unsafe { size_of_val(val_slice as *const [i32]) };
+
+    let val_str: &str = "gccrs";
+    let size_str = unsafe { size_of_val(val_str as *const str) };
+
+    let val_dyn_struct = &val_struct as &dyn TraitA;
+    let size_dyn_struct = unsafe { size_of_val(val_dyn_struct as *const dyn TraitA) };
+
+    let val_u8: u8 = 7;
+    let size_u8 = unsafe { size_of_val(&val_u8 as *const u8) };
+
+    let val_dyn_u8 = &val_u8 as &dyn TraitA;
+    let size_dyn_u8 = unsafe { size_of_val(val_dyn_u8 as *const dyn TraitA) };
+
+    if size_i32 != 4 {
+        1
+    } else if size_struct != 8 {
+        2
+    } else if size_slice != 12 {
+        3
+    } else if size_str != 5 {
+        4
+    } else if size_dyn_struct != 8 {
+        5
+    } else if size_u8 != 1 {
+        6
+    } else if size_dyn_u8 != 1 {
+        7
+    } else {
+        0
+    }
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.