-
-
Notifications
You must be signed in to change notification settings - Fork 15k
core: Add core::ffi::c_intptr_t and core::ffi::c_uintptr_t #156626
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,8 @@ | |||||
| //! This module is intentionally standalone to facilitate parsing when retrieving | ||||||
| //! core C types. | ||||||
|
|
||||||
| use crate::mem::{self}; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| macro_rules! type_alias { | ||||||
| { | ||||||
| $Docfile:tt, $Alias:ident = $Real:ty; | ||||||
|
|
@@ -174,6 +176,129 @@ 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(Copy, Clone, Debug)] | ||||||
| pub struct c_intptr_t(*const ()); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this definition could have an incorrect ABI on some targets since some targets require integers to be sign/zero-extended to fill a register depending on the type's signedness, but if pointers are smaller than a register there is no way for rustc to know if it should sign or zero-extend.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, pointers are not ABI-compatible with any integer type. |
||||||
|
|
||||||
| /// 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(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 { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this trait should probably be sealed |
||||||
| /// 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 { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would make a lot of sense to add a usize/isize constructor as well that creates a without_provenance pointer. This would make it more ergonomic to call APIs that use something like "valid pointer" or magic integer (e.g. |
||||||
| 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! { | ||||||
| any(target_arch = "avr", target_arch = "msp430") => { | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| mod cstr; | ||
| mod intptr; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,23 @@ | ||||||
| #![deny(fuzzy_provenance_casts)] | ||||||
| #![deny(lossy_provenance_casts)] | ||||||
|
|
||||||
| 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() { | ||||||
| // These types should have the same size as a pointer. | ||||||
| assert_eq!(core::mem::size_of::<c_intptr_t>(), core::mem::size_of::<*const ()>()); | ||||||
| assert_eq!(core::mem::size_of::<c_uintptr_t>(), core::mem::size_of::<*const ()>()); | ||||||
|
|
||||||
| let ptr = core::ptr::with_exposed_provenance(16_usize); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| 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); | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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::{TaggedPointer, c_uintptr_t}; | ||
|
|
||
| fn main() { | ||
| let ptr = core::ptr::with_exposed_provenance(16_usize); | ||
| let _ptr_uintptr_t = c_uintptr_t::new(ptr); | ||
| } | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #![crate_type = "lib"] | ||
|
|
||
| use std::ffi::{c_intptr_t}; | ||
| //~^ ERROR use of unstable library feature `c_size_t` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <https://github.com/rust-lang/rust/issues/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`. |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this is a library feature, afaik it doesn't need to be added here
View changes since the review