Reputation: 403
The question is simple but I haven't been able to find the answer. Is the following piece of code valid/safe in Rust:
use core::mem::MaybeUninit;
// This is a ZST
#[derive(Debug)]
struct MyStruct;
// This is an uninhabited type
#[derive(Debug)]
enum MyEnum {}
#[derive(Debug)]
enum OneVariantEnum {
Variant1,
}
fn main() {
let s: MaybeUninit<MyStruct> = MaybeUninit::uninit();
println!("s: {:?}", unsafe { s.assume_init() });
let e: MaybeUninit<MyEnum> = MaybeUninit::uninit();
println!("e: {:?}", unsafe { e.assume_init() });
// and what about this?
let o: MaybeUninit<OneVariantEnum> = MaybeUninit::uninit();
println!("o: {:?}", unsafe { o.assume_init() });
}
Upvotes: 2
Views: 336
Reputation: 155236
The whole point of MaybeUninit::assume_init()
is to convert memory initialized after the call to MaybeUninit::uninit()
into valid values. If the type is zero-sized, then MaybeUninit::uninit().assume_init()
(UB for most types) is actually valid because there is simply no memory to initialize. If it weren't valid, then there would be no way to create ZSTs using MaybeUninit
, and such a limitation is not mentioned in the documentation.
This issue contains a discussion that confirms this in passing.
Note that the above only applies to ZSTs, not to uninhabited types, so constructing MyEnum
is never allowed and that example is UB.
Upvotes: 0
Reputation: 30061
This following seems correct, because MyStruct
is a ZST:
let s: MaybeUninit<MyStruct> = MaybeUninit::uninit();
println!("s: {:?}", unsafe { s.assume_init() });
Constructing a value of an uninhabited type is however always UB, so the following is not correct:
let e: MaybeUninit<MyEnum> = MaybeUninit::uninit();
println!("e: {:?}", unsafe { e.assume_init() });
In debug mode, Rust might catch this and panic with
thread 'main' panicked at 'attempted to instantiate uninhabited type
MyEnum
'
As for OneVariantEnum
, it is a ZST, so it is similar to MyStruct
and the following does not involve UB:
let o: MaybeUninit<OneVariantEnum> = MaybeUninit::uninit();
println!("o: {:?}", unsafe { o.assume_init() });
Upvotes: 2