From b56aaf52e10f979fe9aa9781d8350ce2d4e60023 Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Sat, 16 May 2026 06:29:26 +0800 Subject: [PATCH 1/2] core: Add core::ffi::c_intptr_t and core::ffi::c_uintptr_t Tracking issue: https://github.com/rust-lang/rust/issues/88345 Signed-off-by: Yonggang Luo --- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/ffi/mod.rs | 2 +- library/core/src/ffi/primitives.rs | 20 ++++++++++++++++++ library/coretests/tests/ffi.rs | 1 + library/coretests/tests/ffi/intptr.rs | 17 +++++++++++++++ library/coretests/tests/lib.rs | 1 + library/std/src/ffi/mod.rs | 2 +- .../src/language-features/c-size-t.md | 21 +++++++++++++++++++ .../ui/feature-gates/feature-gate-c-size-t.rs | 4 ++++ .../feature-gate-c-size-t.stderr | 13 ++++++++++++ 11 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 library/coretests/tests/ffi/intptr.rs create mode 100644 src/doc/unstable-book/src/language-features/c-size-t.md create mode 100644 tests/ui/feature-gates/feature-gate-c-size-t.rs create mode 100644 tests/ui/feature-gates/feature-gate-c-size-t.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8385c320d377d..2100893638161 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -422,6 +422,8 @@ declare_features! ( (unstable, avx10_target_feature, "1.88.0", Some(138843)), /// Target features on bpf. (unstable, bpf_target_feature, "1.54.0", Some(150247)), + /// Allows using size_t/ssize_t/uintptr_t/intptr_t/ptrdiff_t. + (unstable, c_size_t, "CURRENT_RUSTC_VERSION", Some(88345)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows defining c-variadic functions on targets where this feature has not yet diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 69ed7314855f9..ca41b17c355ba 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -545,6 +545,7 @@ symbols! { builtin_syntax, bundle, c_dash_variadic, + c_size_t, c_str_literals, c_unwind, c_variadic, diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 3f1aa54050a31..ecf5d54c87e12 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -38,7 +38,7 @@ pub use self::primitives::{ c_ulong, c_ulonglong, c_ushort, }; #[unstable(feature = "c_size_t", issue = "88345")] -pub use self::primitives::{c_ptrdiff_t, c_size_t, c_ssize_t}; +pub use self::primitives::{c_intptr_t, c_ptrdiff_t, c_size_t, c_ssize_t, c_uintptr_t}; // N.B., for LLVM to recognize the void pointer type and by extension // functions like malloc(), we need to have it represented as i8* in diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs index 11dad9a65470c..431c6faa473fe 100644 --- a/library/core/src/ffi/primitives.rs +++ b/library/core/src/ffi/primitives.rs @@ -174,6 +174,26 @@ pub type c_ptrdiff_t = isize; #[unstable(feature = "c_size_t", issue = "88345")] pub type c_ssize_t = isize; +/// Equivalent to C's `intptr_t` type. +/// +/// This type have the same size with a pointer. The C standard technically only +/// requires that this type be a signed integer type just capable of holding a +/// pointer. +#[unstable(feature = "c_size_t", issue = "88345")] +#[repr(transparent)] +#[derive(Debug)] +pub struct c_intptr_t(pub *const ()); + +/// Equivalent to C's `uintptr_t` type. +/// +/// This type have the same size with a pointer. The C standard technically only +/// requires that this type be an unsigned integer type just capable of holding +/// a pointer. +#[unstable(feature = "c_size_t", issue = "88345")] +#[repr(transparent)] +#[derive(Debug)] +pub struct c_uintptr_t(pub *const ()); + mod c_int_definition { crate::cfg_select! { any(target_arch = "avr", target_arch = "msp430") => { diff --git a/library/coretests/tests/ffi.rs b/library/coretests/tests/ffi.rs index 2b33fbd95f073..3110413df7547 100644 --- a/library/coretests/tests/ffi.rs +++ b/library/coretests/tests/ffi.rs @@ -1 +1,2 @@ mod cstr; +mod intptr; diff --git a/library/coretests/tests/ffi/intptr.rs b/library/coretests/tests/ffi/intptr.rs new file mode 100644 index 0000000000000..04a4debe16501 --- /dev/null +++ b/library/coretests/tests/ffi/intptr.rs @@ -0,0 +1,17 @@ +#![deny(fuzzy_provenance_casts)] +#![deny(lossy_provenance_casts)] + +use core::ffi::{c_intptr_t, c_uintptr_t}; + +#[test] +fn test_intptr_unitptr() { + // These types should have the same size as a pointer. + assert_eq!(core::mem::size_of::(), core::mem::size_of::<*const ()>()); + assert_eq!(core::mem::size_of::(), core::mem::size_of::<*const ()>()); + + let ptr = core::ptr::with_exposed_provenance(16_usize); + let ptr_uintptr_t = c_uintptr_t(ptr); + let ptr_back = ptr_uintptr_t.0; + assert_eq!(ptr_back.addr(), 16_usize); + assert_eq!(ptr, ptr_back); +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 12b81fea9d27c..b0bebc92d42d9 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -11,6 +11,7 @@ #![feature(bool_to_result)] #![feature(borrowed_buf_init)] #![feature(bstr)] +#![feature(c_size_t)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_internals)] #![feature(clone_to_uninit)] diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 999bd5e63dc45..7bc4ab7f02895 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -179,7 +179,7 @@ pub use core::ffi::{ c_ulong, c_ulonglong, c_ushort, }; #[unstable(feature = "c_size_t", issue = "88345")] -pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t}; +pub use core::ffi::{c_intptr_t, c_ptrdiff_t, c_size_t, c_ssize_t, c_uintptr_t}; #[doc(inline)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] diff --git a/src/doc/unstable-book/src/language-features/c-size-t.md b/src/doc/unstable-book/src/language-features/c-size-t.md new file mode 100644 index 0000000000000..8dfcaad625f23 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/c-size-t.md @@ -0,0 +1,21 @@ +# `c_size_t` + +The tracking issue for this feature is: [#88345] + +[#88345]: https://github.com/rust-lang/rust/issues/88345 +----- + +The `c_size_t` feature allows to enable C FFI types `size_t` `ssize_t` `intptr_t` `uintptr_t` `ptrdiff_t`. + +## Example + +```rust +#![feature(c_size_t)] + +use std::ffi::{c_intptr_t, c_ptrdiff_t, c_size_t, c_ssize_t, c_uintptr_t}; + +fn main() { + let ptr = core::ptr::with_exposed_provenance(16_usize); + let _ptr_uintptr_t = c_uintptr_t(ptr); +} +``` diff --git a/tests/ui/feature-gates/feature-gate-c-size-t.rs b/tests/ui/feature-gates/feature-gate-c-size-t.rs new file mode 100644 index 0000000000000..22aef2d366578 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c-size-t.rs @@ -0,0 +1,4 @@ +#![crate_type = "lib"] + +use std::ffi::{c_intptr_t}; +//~^ ERROR use of unstable library feature `c_size_t` diff --git a/tests/ui/feature-gates/feature-gate-c-size-t.stderr b/tests/ui/feature-gates/feature-gate-c-size-t.stderr new file mode 100644 index 0000000000000..cb1440b8faaad --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c-size-t.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `c_size_t` + --> $DIR/feature-gate-c-size-t.rs:3:16 + | +LL | use std::ffi::{c_intptr_t}; + | ^^^^^^^^^^ + | + = note: see issue #88345 for more information + = help: add `#![feature(c_size_t)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 4eddacd3be6c19794398604f6117fb84274aa8b2 Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Mon, 18 May 2026 17:41:14 +0800 Subject: [PATCH 2/2] core/ffi: Add trait TaggedPointer IntPtr for hidden intptr_t uintptr_t detail Signed-off-by: Yonggang Luo --- library/core/src/ffi/mod.rs | 6 +- library/core/src/ffi/primitives.rs | 113 +++++++++++++++++- library/coretests/tests/ffi/intptr.rs | 12 +- library/std/src/ffi/mod.rs | 6 +- .../src/language-features/c-size-t.md | 4 +- 5 files changed, 128 insertions(+), 13 deletions(-) diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index ecf5d54c87e12..2507bb493c7ab 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -32,13 +32,15 @@ mod va_list; pub use self::va_list::{VaArgSafe, VaList}; mod primitives; +#[unstable(feature = "c_size_t", issue = "88345")] +pub use self::primitives::{ + IntPtr, TaggedPointer, c_intptr_t, c_ptrdiff_t, c_size_t, c_ssize_t, c_uintptr_t, +}; #[stable(feature = "core_ffi_c", since = "1.64.0")] pub use self::primitives::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong, c_ushort, }; -#[unstable(feature = "c_size_t", issue = "88345")] -pub use self::primitives::{c_intptr_t, c_ptrdiff_t, c_size_t, c_ssize_t, c_uintptr_t}; // N.B., for LLVM to recognize the void pointer type and by extension // functions like malloc(), we need to have it represented as i8* in diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs index 431c6faa473fe..92732d276203f 100644 --- a/library/core/src/ffi/primitives.rs +++ b/library/core/src/ffi/primitives.rs @@ -3,6 +3,8 @@ //! This module is intentionally standalone to facilitate parsing when retrieving //! core C types. +use crate::mem::{self}; + macro_rules! type_alias { { $Docfile:tt, $Alias:ident = $Real:ty; @@ -181,8 +183,8 @@ pub type c_ssize_t = isize; /// pointer. #[unstable(feature = "c_size_t", issue = "88345")] #[repr(transparent)] -#[derive(Debug)] -pub struct c_intptr_t(pub *const ()); +#[derive(Copy, Clone, Debug)] +pub struct c_intptr_t(*const ()); /// Equivalent to C's `uintptr_t` type. /// @@ -191,8 +193,111 @@ pub struct c_intptr_t(pub *const ()); /// a pointer. #[unstable(feature = "c_size_t", issue = "88345")] #[repr(transparent)] -#[derive(Debug)] -pub struct c_uintptr_t(pub *const ()); +#[derive(Copy, Clone, Debug)] +pub struct c_uintptr_t(*const ()); + +/// Trait for types that can be used to represent C's `intptr_t` and `uintptr_t` types. +/// +/// For handle interchange of rust `pointer` type and C's `intptr_t` and `uintptr_t` types. +#[unstable(feature = "c_size_t", issue = "88345")] +#[rustc_const_unstable(feature = "c_size_t", issue = "88345")] +pub const trait TaggedPointer { + /// Creates a new instance of IntPtr from a pointer. + #[unstable(feature = "c_size_t", issue = "88345")] + fn new(ptr: *const ()) -> Self; + /// Returns the pointer contained in IntPtr. + #[unstable(feature = "c_size_t", issue = "88345")] + fn ptr(&self) -> *const (); +} + +/// Trait for retrieving the integer representation of a TaggedPointer. +/// +#[unstable(feature = "c_size_t", issue = "88345")] +pub trait IntPtr: TaggedPointer { + /// The integer type that can hold the tagged pointer value. + type Number; + + /// Returns the integer representation of the pointer contained in IntPtr. + #[unstable(feature = "c_size_t", issue = "88345")] + fn integer(&self) -> Self::Number; +} + +#[unstable(feature = "c_size_t", issue = "88345")] +#[rustc_const_unstable(feature = "c_size_t", issue = "88345")] +impl const TaggedPointer for c_intptr_t { + fn new(ptr: *const ()) -> Self { + Self(ptr) + } + + fn ptr(&self) -> *const () { + self.0 + } +} + +#[unstable(feature = "c_size_t", issue = "88345")] +impl IntPtr for c_intptr_t { + type Number = c_intptr_definition::c_intptr_t; + + fn integer(&self) -> Self::Number { + // A pointer-to-integer transmute currently has exactly the right semantics: it returns the + // integer representing the pointer without exposing the provenance. Note that this is *not* + // a stable guarantee about transmute semantics, it relies on sysroot crates having special status. + // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the + // provenance). + unsafe { mem::transmute(self.0.cast::<()>()) } + } +} + +#[unstable(feature = "c_size_t", issue = "88345")] +#[rustc_const_unstable(feature = "c_size_t", issue = "88345")] +impl const TaggedPointer for c_uintptr_t { + fn new(ptr: *const ()) -> Self { + Self(ptr) + } + + fn ptr(&self) -> *const () { + self.0 + } +} + +#[unstable(feature = "c_size_t", issue = "88345")] +impl IntPtr for c_uintptr_t { + type Number = c_intptr_definition::c_uintptr_t; + + fn integer(&self) -> Self::Number { + // A pointer-to-integer transmute currently has exactly the right semantics: it returns the + // integer representing the pointer without exposing the provenance. Note that this is *not* + // a stable guarantee about transmute semantics, it relies on sysroot crates having special status. + // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the + // provenance). + unsafe { mem::transmute(self.0.cast::<()>()) } + } +} + +mod c_intptr_definition { + crate::cfg_select! { + target_pointer_width = "16" => { + pub(super) type c_intptr_t = i16; + pub(super) type c_uintptr_t = u16; + } + target_pointer_width = "32" => { + pub(super) type c_intptr_t = i32; + pub(super) type c_uintptr_t = u32; + } + target_pointer_width = "64" => { + pub(super) type c_intptr_t = i64; + pub(super) type c_uintptr_t = u64; + } + _ => { + /// 128-bit width pointer. + /// + /// The C standard only requires that these types be large enough to hold a pointer, + /// so we'll use the i128/u128 integer types in Rust. + pub(super) type c_intptr_t = i128; + pub(super) type c_uintptr_t = u128; + } + } +} mod c_int_definition { crate::cfg_select! { diff --git a/library/coretests/tests/ffi/intptr.rs b/library/coretests/tests/ffi/intptr.rs index 04a4debe16501..5224fedaa46f4 100644 --- a/library/coretests/tests/ffi/intptr.rs +++ b/library/coretests/tests/ffi/intptr.rs @@ -1,7 +1,11 @@ #![deny(fuzzy_provenance_casts)] #![deny(lossy_provenance_casts)] -use core::ffi::{c_intptr_t, c_uintptr_t}; +use core::ffi::{IntPtr, TaggedPointer, c_intptr_t, c_uintptr_t}; + +extern "C" fn c_ffi_function_on_uintptr(v: c_uintptr_t) { + assert_eq!((v.integer() as usize) & 0xFF_usize, 16_usize); +} #[test] fn test_intptr_unitptr() { @@ -10,8 +14,10 @@ fn test_intptr_unitptr() { assert_eq!(core::mem::size_of::(), core::mem::size_of::<*const ()>()); let ptr = core::ptr::with_exposed_provenance(16_usize); - let ptr_uintptr_t = c_uintptr_t(ptr); - let ptr_back = ptr_uintptr_t.0; + let ptr_uintptr_t = c_uintptr_t::new(ptr); + let ptr_back = ptr_uintptr_t.ptr(); + c_ffi_function_on_uintptr(ptr_uintptr_t); assert_eq!(ptr_back.addr(), 16_usize); + assert_eq!((ptr_uintptr_t.integer() as usize) & 0xFF_usize, 16_usize); assert_eq!(ptr, ptr_back); } diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 7bc4ab7f02895..5e8a997eb82f3 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -166,6 +166,10 @@ pub mod c_str; #[stable(feature = "core_c_void", since = "1.30.0")] pub use core::ffi::c_void; +#[unstable(feature = "c_size_t", issue = "88345")] +pub use core::ffi::{ + IntPtr, TaggedPointer, c_intptr_t, c_ptrdiff_t, c_size_t, c_ssize_t, c_uintptr_t, +}; #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ @@ -178,8 +182,6 @@ pub use core::ffi::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong, c_ushort, }; -#[unstable(feature = "c_size_t", issue = "88345")] -pub use core::ffi::{c_intptr_t, c_ptrdiff_t, c_size_t, c_ssize_t, c_uintptr_t}; #[doc(inline)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] diff --git a/src/doc/unstable-book/src/language-features/c-size-t.md b/src/doc/unstable-book/src/language-features/c-size-t.md index 8dfcaad625f23..aa4e282c02b2e 100644 --- a/src/doc/unstable-book/src/language-features/c-size-t.md +++ b/src/doc/unstable-book/src/language-features/c-size-t.md @@ -12,10 +12,10 @@ The `c_size_t` feature allows to enable C FFI types `size_t` `ssize_t` `intptr_t ```rust #![feature(c_size_t)] -use std::ffi::{c_intptr_t, c_ptrdiff_t, c_size_t, c_ssize_t, c_uintptr_t}; +use std::ffi::{TaggedPointer, c_uintptr_t}; fn main() { let ptr = core::ptr::with_exposed_provenance(16_usize); - let _ptr_uintptr_t = c_uintptr_t(ptr); + let _ptr_uintptr_t = c_uintptr_t::new(ptr); } ```