-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Tracking issue for std::ptr::NonNull::cast #47653
Comments
Would it be possible to add a |
How would that work? How does this method you pick a vtable or a slice length? The only way I know in safe Rust (other than ad-hoc APIs like #![feature(box_into_raw_non_null)]
use std::ptr::NonNull;
fn main() {
// Creating thin pointers
let a: NonNull<[u8; 10]> = Box::into_raw_non_null(Box::new([42; 10]));
let b: NonNull<String> = Box::into_raw_non_null(Box::new(String::new()));
// Coercing to fat pointers to dynamically-sized types
let _a: NonNull<[u8]> = a;
let _b: NonNull<std::fmt::Display> = b;
} |
I suppose I was thinking particularly about statically typed but dynamically sized fat pointers (e.g., to slices). I'm not sure how you'd answer the question about vtables. So, concretely, converting between, e.g., |
Turns out you can cast a raw slice to another. This leaves the length unchanged regardless of the item type, which is often wrong. For example, this compiles and prints random (stack?) memory. fn main() {
let b = [1, 2, 3, 4, 5];
let ptr = cast_slice::<u8, u64>(&b);
for x in unsafe { &*ptr } {
println!("{:016x}", x)
}
}
fn cast_slice<T, U>(s: *const [T]) -> *const [U] {
s as _
} However that’s the case where the types on both sides of |
Does that also work for structs with the last field as an unsized slice?
(On my phone; can't test)
…On Jan 22, 2018 1:39 AM, "Simon Sapin" ***@***.***> wrote:
Turns out you can cast a raw slice to another. This leaves the length
unchanged regardless of the item type, which is often wrong. For example,
this compiles and prints random (stack?) memory.
fn main() {
let b = [1, 2, 3, 4, 5];
let ptr = cast_slice::<u8, u64>(&b);
for x in unsafe { &*ptr } {
println!("{:016x}", x)
}
}
fn cast_slice<T, U>(s: *const [T]) -> *const [U] {
s as _
}
However that’s the case where the types on both sides of as are known to
be raw slices. In the fully-generic ?Sized case the compiler doesn’t know
what code to emit.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#47653 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AA_2L_Rj579HpWdWeA2g0Hykoi51veOeks5tNFdKgaJpZM4RmTjN>
.
|
This compiles, however wrong it may be: fn main() {
struct Foo(u8, [u8]);
struct Bar(String, [u64]);
let ptr: *const Foo = unimplemented!();
ptr as *const Bar;
} But this is still slice to slice. If trait objects are involved, they need to be the same trait. At least that’s the current implementation of |
OK, probably worth it to just stick with |
This one-line method landed in Nightly on 2018-02-07. If stabilized in the current 1.26 cycle, it will reach Stable on 2018-05-11 after four months. @aturon, is this enough baking time to start FCP? |
#49669 adds a TR;DR: Despite limitations I think we should stabilize this as-is. @rfcbot fcp merge |
Team member @SimonSapin has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
stabilize a bunch of minor api additions besides `ptr::NonNull::cast` (which is 4 days away from end of FCP) all of these have been finished with FCP for a few weeks now with minimal issues raised * Closes #41020 * Closes #42818 * Closes #44030 * Closes #44400 * Closes #46507 * Closes #47653 * Closes #46344 the following functions will be stabilized in 1.27: * `[T]::rsplit` * `[T]::rsplit_mut` * `[T]::swap_with_slice` * `ptr::swap_nonoverlapping` * `NonNull::cast` * `Duration::from_micros` * `Duration::from_nanos` * `Duration::subsec_millis` * `Duration::subsec_micros` * `HashMap::remove_entry`
Ran into the issue where I can't cast between NonNull slice types. |
fn main() {
let a: *const [u8] = b"foo";
println!("{:04x?}", unsafe { &*(a as *const [u16]) })
} Playground, output:
The You can use |
I understand that you can do unsafe (and unsound) things when casting pointers. |
It’s already discussed above why we can’t just add |
That actually might be useful if only to give us a place to document the footgun that is casting slice pointers. Since it's a keyword, |
Yes, except I think it should just be called |
@joshlf rustdoc does support documenting keywords, these days: @jethrogb Re calling it |
Hmm I half-expected an impl coherence error, but this compiles. I’m not sure how I feel about potentially adding it to the standard library though. unsafe trait Cast<T: ?Sized> {
fn cast(ptr: *mut Self) -> *mut T;
}
// implied: T: Sized
unsafe impl<T, U: ?Sized> Cast<T> for U {
fn cast(ptr: *mut Self) -> *mut T {
ptr as _
}
}
unsafe impl<T, U> Cast<[T]> for [U] {
fn cast(slice: *mut Self) -> *mut [T] {
unsafe {
let ptr = (*slice).as_mut_ptr();
let len = (*slice).len();
std::slice::from_raw_parts_mut(ptr as _, len)
}
}
} |
No need for a trait: struct Ptr<T: ?Sized>(*const T);
impl<T> Ptr<T> {
fn cast<U>(self) -> Ptr<U> {
Ptr(self.0 as *const _)
}
}
impl<T> Ptr<[T]> {
fn cast<U>(self) -> Ptr<[U]> {
Ptr(self.0 as *const _)
}
} |
@jethrogb That code doesn’t have |
Yes, you're right, I didn't look at the docs in detail enough to see that existing bound |
ptr::NonNull<T>
is similar to*mut T
. Itscast
method added in #47631 is similar to raw pointer casting with theas
operator.Note that
T
is?Sized
butU
is not (or we’d get a E0606 "vtable kinds may not match" error onas
)The text was updated successfully, but these errors were encountered: