Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upImplement `MaybeUninit` #53508
Conversation
rust-highfive
assigned
RalfJung
Aug 19, 2018
rust-highfive
added
the
S-waiting-on-review
label
Aug 19, 2018
Mark-Simulacrum
reviewed
Aug 19, 2018
|
Looks like there might be a few cases where we're not performing the right change here? |
| /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. | ||
| /// It is your responsibility to make sure `T` gets dropped if it got initialized. | ||
| #[unstable(feature = "maybe_uninit", issue = "53491")] | ||
| pub const fn uninitialized() -> MaybeUninit<T> { |
This comment has been minimized.
This comment has been minimized.
Mark-Simulacrum
Aug 19, 2018
Member
Do we need a rustc_const_unstable attribute here as well? Or at least make a note to do so eventually?
This comment has been minimized.
This comment has been minimized.
|
|
||
| // Perform the swap | ||
| copy_nonoverlapping(x, &mut tmp, 1); | ||
| copy_nonoverlapping(x, tmp.get_mut(), 1); |
This comment has been minimized.
This comment has been minimized.
| copy_nonoverlapping(src, &mut tmp, 1); | ||
| tmp | ||
| let mut tmp = MaybeUninit::<T>::uninitialized(); | ||
| copy_nonoverlapping(src, tmp.get_mut(), 1); |
This comment has been minimized.
This comment has been minimized.
Mark-Simulacrum
Aug 19, 2018
Member
This also looks like it should be as_mut_ptr? tmp is not initialized at this point.
| let rawarray = RawArray::new(); | ||
| let buf = rawarray.ptr(); | ||
| let rawarray = MaybeUninit::<RawArray<T>>::uninitialized(); | ||
| let buf = rawarray.get_ref().ptr(); |
This comment has been minimized.
This comment has been minimized.
Mark-Simulacrum
Aug 19, 2018
Member
Isn't this also not legitimate code? get_ref is only defined as far as I can tell on initialized memory, but it's not initialized here.
| start_l = offsets_l.as_mut_ptr(); | ||
| end_l = offsets_l.as_mut_ptr(); | ||
| start_l = unsafe { offsets_l.get_mut().as_mut_ptr() }; | ||
| end_l = unsafe { offsets_l.get_mut().as_mut_ptr() }; |
This comment has been minimized.
This comment has been minimized.
Mark-Simulacrum
Aug 19, 2018
Member
Isn't this also invalid? I believe offsets_l is uninitialized at this point?
| @@ -288,8 +288,8 @@ fn partition_in_blocks<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize | |||
|
|
|||
| if start_r == end_r { | |||
| // Trace `block_r` elements from the right side. | |||
| start_r = offsets_r.as_mut_ptr(); | |||
| end_r = offsets_r.as_mut_ptr(); | |||
| start_r = unsafe { offsets_r.get_mut().as_mut_ptr() }; | |||
This comment has been minimized.
This comment has been minimized.
Mark-Simulacrum
Aug 19, 2018
Member
This code also looks like this should be invalid? At least, offsets_r is not necessarily initialized, right?
scottmcm
reviewed
Aug 19, 2018
| keys: [K; CAPACITY], | ||
| vals: [V; CAPACITY], | ||
| keys: MaybeUninit<[K; CAPACITY]>, | ||
| vals: MaybeUninit<[V; CAPACITY]>, |
This comment has been minimized.
This comment has been minimized.
scottmcm
Aug 19, 2018
Member
Based on the comment above, should this instead be [MaybeUninit<V>; CAPACITY]?
(That might be a pain, though, and this is no worse than before, so might not be this PR.)
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
eddyb
Aug 22, 2018
Member
Should we document that you can partially-initialize MaybeUninit, i.e. that it "distributes over products"?
This comment has been minimized.
This comment has been minimized.
RalfJung
Aug 22, 2018
Member
I guess this is forth saying, yes.
Unfortunately actually implementing this is not easy, same problem as for Cell (which also distributes over products).
This comment has been minimized.
This comment has been minimized.
|
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 |
eddyb
reviewed
Aug 20, 2018
| @@ -784,6 +784,14 @@ impl Abi { | |||
| _ => false, | |||
| } | |||
| } | |||
|
|
|||
| /// Returns true if this is an uninhabited type | |||
| pub fn is_uninhabited(&self) -> bool { | |||
This comment has been minimized.
This comment has been minimized.
eddyb
Aug 20, 2018
•
Member
For some reason I would've avoided this but I guess it's fine.
Could you also go through rg '==.*::Uninhabited' and change all of those to use is_uninhabited?
eddyb
reviewed
Aug 20, 2018
| } else { | ||
| "Attempted to instantiate an uninhabited type (e.g. `!`) \ | ||
| using mem::uninitialized()" | ||
| }; |
This comment has been minimized.
This comment has been minimized.
eddyb
Aug 20, 2018
Member
You can actually use format!("... uninhabited type {} using ...", sig.output()) here, heh.
eddyb
reviewed
Aug 20, 2018
| @@ -462,6 +462,55 @@ impl FunctionCx<'a, 'll, 'tcx> { | |||
| return; | |||
| } | |||
|
|
|||
| if (intrinsic == Some("init") || intrinsic == Some("uninit")) && | |||
| bx.cx.layout_of(sig.output()).abi.is_uninhabited() | |||
This comment has been minimized.
This comment has been minimized.
eddyb
Aug 20, 2018
Member
Can you move this below let fn_ty? Then you can use fn_ty.ret.layout instead of calling layout_of.
eddyb
reviewed
Aug 20, 2018
| panic::catch_unwind(|| mem::zeroed::<!>()).is_err(); | ||
|
|
||
| panic::catch_unwind(|| mem::uninitialized::<Foo>()).is_err(); | ||
| panic::catch_unwind(|| mem::zeroed::<Foo>()).is_err(); |
This comment has been minimized.
This comment has been minimized.
eddyb
Aug 20, 2018
•
Member
I think you can also do:
assert_eq!(....downcast_ref::<&'static str>(), Some("panic message"));
This comment has been minimized.
This comment has been minimized.
|
Looks like the gdb pretty-printing scripts make assumptions about the fields of libstd datastructures: rust/src/etc/debugger_pretty_printers_common.py Lines 392 to 401 in 6bf6d50 |
RalfJung
reviewed
Aug 21, 2018
| @@ -567,7 +567,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> { | |||
| // the node, which is allowed by LLVM. | |||
| unsafe { | |||
| slice::from_raw_parts( | |||
| self.as_leaf().keys.as_ptr(), | |||
| self.as_leaf().keys.get_ref().as_ptr(), | |||
This comment has been minimized.
This comment has been minimized.
RalfJung
Aug 21, 2018
Member
Here and below, can't you use MaybeUninit::as_ptr/MaybeUninit::as_mut_ptr?
RalfJung
reviewed
Aug 21, 2018
| let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, | ||
| *num, sign, precision, | ||
| false, &mut buf, &mut parts); | ||
| false, buf.get_mut(), parts.get_mut()); |
This comment has been minimized.
This comment has been minimized.
RalfJung
reviewed
Aug 21, 2018
| struct Foo { | ||
| x: u8, | ||
| y: !, | ||
| } |
This comment has been minimized.
This comment has been minimized.
RalfJung
Aug 21, 2018
Member
Could you add a test for an empty enum?
Also, AFAIK Foo is NOT layout-uninhabited, because of #49298?
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
eddyb
Aug 22, 2018
Member
Wait, no, check this out:
#![feature(never_type)]
pub struct Foo { x: u8, y: ! }
pub fn foo() -> Foo { loop {} }That gets noreturn in the LLVM IR, with u8 or () in the first field, but if you change the ! to (), you lose the noreturn.
What happened in the first for #49298 is we kept the layout-uninhabited property propagated, but it wouldn't affect type sizes the same.
Which means we can use the check here to detect noreturn UB in all relevant cases!
This comment has been minimized.
This comment has been minimized.
RalfJung
Aug 22, 2018
Member
nocall would be more correct than noreturn though :P
Which "check here"?
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
I finally wrote that blog post about whether and when |
japaric
force-pushed the
japaric:maybe-uninit
branch
from
c9fe28f
to
a56ee4e
Aug 23, 2018
This comment has been minimized.
This comment has been minimized.
|
I believe I have addressed all the review comments, except for the one about gdb scripts -- I'll check that one later. Let me know if I missed something! |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
Ping from triage @RalfJung! This PR needs your review. |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
There are still several uses of Otherwise, r=me once Travis is happy with the gdb stuff. |
RalfJung
added
S-waiting-on-author
and removed
S-waiting-on-review
labels
Aug 28, 2018
cramertj
referenced this pull request
Aug 29, 2018
Closed
RFC: Direct and Partial Initialization using &uninit T #2534
This comment has been minimized.
This comment has been minimized.
|
Sorry for the delay! I'm looking again at this. This is one of the debuginfo tests that's failing: rust/src/test/debuginfo/nil-enum.rs Lines 30 to 43 in fea32f1 The test is instantiating nil enums and then inspecting them in GDB. The program now panics with the changes mode in this PR so the test broke. I'm not quite sure what to do here. Should I instantiate |
This comment has been minimized.
This comment has been minimized.
|
Yeah that test is definitely UB. It might still be worth seeing how gbd displays that. So maybe add a comment saying it is UB, and then use |
japaric
force-pushed the
japaric:maybe-uninit
branch
from
a56ee4e
to
2327942
Sep 1, 2018
This comment has been minimized.
This comment has been minimized.
|
Rebased and fixed the debuginfo tests in the last two commits. Regarding using I have explored the two options by re-implementing one function using both approaches. I have pushed my work in two branches which are linked above. Neither feels ergonomic (the first approach actually feels wrong because it constrains the argument) but the second option is slightly better except for the fact that instantiating |
This comment has been minimized.
This comment has been minimized.
|
Is it UB to transmute |
This comment has been minimized.
This comment has been minimized.
|
No, definitely not. |
This comment has been minimized.
This comment has been minimized.
|
It's a significant perf regression:
@japaric: can you investigate? Here are docs on benchmarking and profiling. Cachegrind can be particularly useful for examining the difference between two compiler versions. |
This comment has been minimized.
This comment has been minimized.
|
On second thought, this regression is bad enough that I think we should consider backing the changes out. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
I support backing this change out to investigate performance losses. |
This comment has been minimized.
This comment has been minimized.
|
Fine for me. I assume the regression comes from one of the places where |
RalfJung
added a commit
to RalfJung/rust
that referenced
this pull request
Sep 25, 2018
RalfJung
referenced this pull request
Sep 25, 2018
Merged
Revert most of MaybeUninit, except for the new API itself #54554
This comment has been minimized.
This comment has been minimized.
|
Revert submitted as #54554 |
japaric commentedAug 19, 2018
This PR:
MaybeUninit(see #53491) to{core,std}::mem.mem::{uninitialized,zeroed}panic when they are used to instantiate an uninhabited type.mem::{uninitialized,zeroed}just yet. As per #53491 (comment), we should not deprecate them untilMaybeUninitis stabilized.mem::{uninitialized,zeroed}in core and alloc withMaybeUninit.There are still several instances of
mem::{uninitialized,zeroed}instdthat this PR doesn't address.r? @RalfJung
cc @eddyb you may want to look at the new panicking logic