-
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
Make core::mem::MaybeUninit::zeroed a const fn #54832
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
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 believe miri zero-fills allocations, and that force_allocation is the right way to allocate something in miri, but if either of those assumptions are incorrect please let me know.
While the "byte" representation is zero filled, there's also a layer marking these bytes as "uninitialized". Only after looking at all three layers (bytes, initialized, relocation/pointer) can one make a statement about the value.
@@ -150,6 +150,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> | |||
} | |||
self.write_scalar(val, dest)?; | |||
} | |||
"init" => { | |||
self.force_allocation(dest)?; |
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.
You can just copy the implementation from https://github.com/solson/miri/blob/master/src/intrinsic.rs#L238
Your current implementation is a nop, it literally does nothing ;)
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.
Dang, that was awfully naive of me ha. Done.
Side question: is there any reason that entire file isn't just copied into here?
r? @oli-obk |
Thank you, @oli-obk, for helping walk me through this one! |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
Uh... I am not a big fan. :/ The plan is to get rid of these horrible intrinsics ( I'd much prefer keeping the original implementation of |
(Sorry, somehow I managed to submit the same thing twice and close the PR and I have no idea how that happened.) So, to be clear: If you are asking for my opinion, I'll |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
Dang. I originally wanted to implement this by just transmuting a |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
|
Use this to implement MaybeUninit::zeroed, and make the init intrinsic no longer const
Okay, I've added a commit that reverts |
pub const fn zeroed() -> MaybeUninit<T> { | ||
let mut u = MaybeUninit::<T>::uninitialized(); | ||
unsafe { | ||
(&mut *u.value as *mut T).write_bytes(0u8, 1); |
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.
Why not make as_mut_ptr
a const fn
as well and avoid duplicating?
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've been digging into making that change, but I keep running into issues like this, and now that I think of it, I can't figure out why this even compiles in the first place:
ManuallyDrop
implements the deref traits, but those functions aren'tconst
.- I only made the intrinsic
write_bytes
const
, not thewrite_bytes
method formut_ptr
lang item. This should be using the latter, not the intrinsic. - This requires taking a mutable reference.
I don't understand why this even works as-is. Trying to make as_mut_ptr
a const fn
reveals all these issues, but manually inlining it here does not...
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.
O_o, that looks like a hole in the const checks, but I don't even know where to start debugging this. Even if the function isn't checked for min_const_fn
, it should definitely fail to build due to the regular const fn checks.
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.
Yea, in the playground this won't compile: https://play.rust-lang.org/?gist=adce30a361142dcea174aee030ea8a91&version=nightly&mode=debug&edition=2018
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.
Could this be related to what #54715 fixes?
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.
No, I think I found it. is_min_const_fn
doesn't check for is_const_fn
as a prerequisite.
The fix is to add self.is_const_fn(def_id) &&
infront of
rust/src/librustc/ty/constness.rs
Line 43 in 567557f
if self.features().staged_api { |
count, mplace.layout.size.bytes(), intrinsic_name), | ||
)); | ||
} | ||
} |
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.
Why is this code so different from https://github.com/solson/miri/blob/master/src/intrinsic.rs#L420 ?
Also note that the ZST optimization here is wrong. It is UB to call write_bytes
on an unaligned pointer even for a ZST. Your code fails to check for that.
&format!("The use of std::ptr::write_bytes() \ | ||
is gated in {}s", self.mode)); | ||
} | ||
} |
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.
Why does this logic look different than the one for transmute
above?
Yes, I'm in favor of this approach. :) Please remove the old commits though, no reason to keep them. |
I'm unsure how to proceed here. As best as I can tell, in order to implement this (without a const
Items 1 and 2 are easy, but item 3 seems to be the real blocker. Any advice on how to proceed? |
is 3. solvable with the |
No,
|
hmm... this is a little tricky to solve. The checks are there so we don't end up with a |
Ping from triage! What is the status of this PR? Is it blocked on an external issue? |
yea, @mjbshaw unfortunately I think we can't really do this right now. We need to figure out how to do mutable references in const fns first. This is going to take a while (both in figuring out and implementing). Once we've done that, don't hesitate to reopen your PR |
First, let me say I have no idea what I'm doing, so this might be completely wrong. @RalfJung (and others), please let me know if this accidentally causes undefined behavior.
I believe miri zero-fills allocations, and that
force_allocation
is the right way to allocate something in miri, but if either of those assumptions are incorrect please let me know.I'm happy to add this behind a feature gate (as suggested by @Centril). I didn't here since
MaybeUninit
is already unstable and I'm hoping this isn't too controversial.