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, ¶m_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 ¶m_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 + } +}
