-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Nuke slice_as{,_mut}_ptr methods of MaybeUninit #103133
Conversation
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
r? @m-ou-se (rust-highfive has picked a reviewer for you, use r? to override) |
library/core/src/fmt/num.rs
Outdated
@@ -480,7 +476,7 @@ impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128); | |||
|
|||
/// Helper function for writing a u64 into `buf` going from last to first, with `curr`. | |||
fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut usize) { | |||
let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf); | |||
let buf_ptr = buf.as_mut_ptr().inner(); |
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.
This could potentially be replaced with a bunch of MaybeUninit::write
s, but there are so many of them that I don't want to risk bounds checking perf or use get_unchecked a million times. Though maybe using get_unchecked
a million times is actually better because it shows the unsafety?
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.
add
is already unsafe, so I guess probs not needed.
cf04e53
to
accf4dc
Compare
r? @RalfJung |
This comment has been minimized.
This comment has been minimized.
512e93b
to
0bbb561
Compare
I'm not a libs API person, so I'm the wrong reviewer here. |
Right, keep forgetting, sorry! :) |
@@ -346,7 +341,7 @@ impl FileEncoder { | |||
// room to write the input to the buffer. | |||
unsafe { | |||
let src = buf.as_ptr(); | |||
let dst = MaybeUninit::slice_as_mut_ptr(&mut self.buf).add(buffered); | |||
let dst = self.buf[buffered].as_mut_ptr(); |
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.
This adds a runtime bounds check where there was none before. Same for all the other places where add
became [...]
.
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.
Correct. But the unsafety is centered around copy_nonoverlapping
and presumably llvm can optimize out the bounds checking since it's done right above?
Happy to remove the bounds checking if that's what reviewers want, but either way get_unchecked
is the method designed to express the desire to avoid bounds checking, not pointer addition IMO.
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.
I don't know if the bounds checks here are a problem, I only know I took care to not introduce any new bounds checks when this code was originally ported to MaybeUninit
.
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.
I went back through and removed all the bounds checks that wouldn't be optimized out by the compiler. Anything remaining should be trivially removable.
library/core/src/mem/maybe_uninit.rs
Outdated
|
||
// --- FIXME --- | ||
// Stabilize these as From implementations. | ||
// The only reason they aren't From is because that's insta-stable. |
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.
IMO into
is way to implicit for use around unsafe code. Unsafe code needs clearly stated intent, so just saying "please convert this to something else" is not explicit enough.
So IMO we actually want dedicated methods here, and we need to bikeshed their name. I don't like inner
but I also don't have better suggestions at the moment.
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.
I went with into_inner
to be consistent with other APIs.
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.
I don't know any API this is consistent with? into_inner
is usually for methods of the form Type<T> -> T
; I find it extremely surprising to see it here for a raw pointer method.
Something like as_inner_ptr
or so maybe?
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.
I guess I don't see *const Type<T> -> *const T
as being too different from Type<T> -> T
. I guess the difference is that one is a type cast whereas the other is providing a view into a type.
as_
is supposed to be for borrowed types—are we counting pointers as a kind of borrow for naming purposes? If so as_inner_ptr
seems great or maybe even just as_inner
.
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.
I don't see *const Type -> *const T as being too different from Type -> T
Why not? It makes a huge difference whether ownership is consume vs whether there is a form of "borrowing". We never use into_inner
for methods like &Type<T> -> &T
or &mut Type<T> -> &mut T
. These functions here are very much like them, except they are borrowing via raw pointers, not references.
One similar function we have is UnsafeCell::raw_get
. On MaybeUninit
we already have as_(mut_)ptr
that take references; now here we have the exact same methods using raw pointers so the naming should be similar. raw_as_ptr
sounds odd though...
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.
Gotya, I wasn't really thinking of pointers as references for naming but you're totally right that makes more sense. raw_as_ptr
does seems a little weird, but it would be consistent... will rename.
If you have to add a completely new method to actually replace these methods, then maybe they aren't ready for removal imo. You should add the new method through the correct processes first, and then we can maybe remove these later. Also I agree with Ralf that these should not be From impls at all. |
Agreed. See rust-lang/libs-team#122 (comment). Let's let this sit until the other MaybeUninit stuff is resolved and I'll give this some more thought. @rustbot author |
@SUPERCILEX |
Alrighty, I created rust-lang/libs-team#245 because I think creating a small, focused ACP will help move things forward. |
4684c50
to
4c97cda
Compare
@rustbot ready ACP resolution: rust-lang/libs-team#245 (comment) |
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
4c97cda
to
b602bbf
Compare
Do we need FCP or something for posterity, or should this just be r+'d? Can I even |
I don't think I like this stripped down version - every new use of 'cast' is a step backwards IMO. These are hard to review since one cannot easily tell what they are being cast *from*.
|
Which ones did you think were unnecessary? As far as I am aware, most/all of these are ported from old pre-MaybeUninit code that already did not have bounds checks. So the removal was entirely deliberate, and not related to the signature of these methods. FWIW I agree that with a raw ptr projection method ( |
Take a look at all the places I used slicing operators in num.rs for this commit:
Yeah, that's fair. So do those two changes need to happen together? |
"should have probably" is fairly weak. This is all unsafe code because it is considered performance-sensitive. And this code is old, it used unchecked accesses already before it used Notice all the So this is definitely not evidence that the current API leads to omitted bounds checks.
I would personally prefer that. I don't have the power to block changes in this part of the compiler though. |
Typo that autocorrect keeps trying to put in, sorry. Should have provably. As in if they don't get optimized out it's an llvm bug.
Yeah I think that's reasonable unfortunately. I'll have time to look into this in a month or two again. |
Based on the prev. comment switching to waiting on author to incorporate changes. Feel free to request a review with @rustbot author |
☔ The latest upstream changes (presumably #115542) made this pull request unmergeable. Please resolve the merge conflicts. |
@SUPERCILEX FYI: when a PR is ready for review, send a message containing |
This PR is waiting on me to figure out what to do with |
@SUPERCILEX any updates on this? |
I'll close for now. I still think these methods should be removed, but sadly don't have the time to see that work through right now. |
These methods are of questionable value: they mix together removing bounds checks with converting the MaybeUninit slice into a raw pointer. These two behaviors should be explicitly invoked separately to improve code clarity and safety. There is evidence of unnecessary bounds checking removal in the stdlib uses that are updated in this PR.
In rust-lang/libs-team#122, there is discussion of a need for generalized containers. However, that's going to be a long ways off, so in the meantime this PR adds an
into_inner
method on MaybeUninit raw pointers to unwrap the raw pointer. These aren't strictly necessary and could be replaced bycast
, but then you don't get and type system guarentees.