Closed Zoxc closed 5 years ago
All-bits-zero isn't special in Rust (up to dynamic drops, which are being removed). Allowing some kind of mem::uninitialized()
would be nice, through.
Sounds like CTFE. See https://github.com/rust-lang/rfcs/issues/322 for another proposal that suggested limited CTFE for intrinsic functions.
@mahkoh
We do have a limited version of CTFE. Currently it is limited to arithmetic and constructors. mem::uninitialized()
won't increase its complexity so much .
However, adding size_of
would complicate things more, because constants can be a part of type-checking, and this would make type-checking depend on LLVM. Because recursion in structs is so limited, this would still be tractable, but if we add traits etc. it would be a major mess.
I'm talking about stuff like:
trait Tr { fn doit(&self); }
impl Tr for [uint, ..std::mem::size_of::<uint>()] {
fn doit(&self) { println!("called uint"); }
}
impl Tr for [uint, ..12-std::mem::size_of::<uint>()] {
fn doit(&self) { println!("called 12-uint"); }
}
fn main() {
let s = [0,1,2,3u];
s.doit(); // which .doit is called depends on architecture
}
We could get around this by treating such values as "abstract values", so that they don't interfere with type-checking, and only expand them in trans. Of course this would create 2 kinds of constexprs, but otherwise we would be getting into what seems to me like a pretty deep dependent type hole.
C gets away with this because it "executes" declarations one-by-one.
@arielb1 you can already do that, using uint::BYTES
or uint::BITS
.
uint
was just a simple example, whose size is a well-known constant – you could put more complicated types there so we need to put trans::adt
-s size calculation code into rustc.
AFAIK, the size calculations are done by LLVM. We could have a LLVM context during type-checking, is there anything problematic with that? We should do that anyway instead of the hacks we've thrown around transmute.
@eddyb
They are done via LLVM and a big part of trans. I'll prefer keeping them separate. Actually, if we allow calling trait methods in constexprs then we'll have a total dependent type mess, and I strongly prefer not to go there, so we need to stop somewhere.
There is also the problem of struct -> constexpr recursion. Because there are only finitely many constants we can handle this with a DFS, but if we allow functions this could get more complicated.
A big part of trans? I find it's quite isolated, compared to anything which deals with Block
, for example.
if we allow calling trait methods in constexprs
Nobody said anything about that. You couldn't even use a size_of
intrinsic or associated constant, with a non-concrete type parameter, as the length of an array (e.g. impl<T> Cast<T> for [u8, ..size_of::<T>()]
) because the length has to be constant before monomorphization, though that may change at some point.
Would it be possible to make mem::uninitialized
a const fn
? (or mem::zeroed
?)
@gnzlbg once https://github.com/rust-lang/rust/pull/46882 is merged, that is a trivial addition! (imo even uncontroversial, since you can write an unsafe const fn
yourself that does the same thing via unions).
union Foo<T> {
t: T,
u: (),
}
unsafe const fn uninitialized<T>() -> T {
Foo { u: () }.t
}
@oli-obk congrats on the merge of that PR :)
Any news about this? This issue comes up every now and then in stdsimd
: https://github.com/rust-lang-nursery/stdsimd/issues/403#issuecomment-376354681
My feeling is that someone should just open a PR and we FCP it, because you can do zeroed/uninitialized with horrible hacks in constants, so why not allow the nice obvious ways, too!?
Implementation guide: grep for "size_of"
(yes with quotes) in rustc, grep for "uninitialized"
in the miri repository, copy over code from the miri repository to rustc.
@oli-obk can you give some more hints? I can't find any code for "uninitialized" in miri that looks like the const eval stuff in librustc_mir/interpret/const_eval. Also, would I need to add uninitialized/zeroed to the intrinsics?
So... I've been told that these intrinsics should not exist due to various unsafety rules not playing nice with them.
Instead of creating a static/const with one of these intrinsics, your static/const should be of Union type with a zst variant that you use to "initialize" it.
I'm not sure this issue can be acted on. Maybe we should close it?
cc @RalfJung
Seems like essentially a duplicate of https://github.com/rust-lang/rust/pull/50150 to me.
Instead, we should strive to stabilize MaybeUninit
and make it usable from const context.
I've now read the other issue & the MaybeUninit RFC and it does seem like this is a duplicate of the other issue. Maybe close this so no-one tries to implement it?
Closing as ~"completed".
There should be a way to create consts, statics and static muts which are partially or fully uninitialized or zeroed.
One way to do this could be to create built-in unsafe generic constants ZEROED and UNDEF.
@eddyb suggested to make the existing intrinsics usable in statics
A crude solution could be to allow the initializer in a static mut to be left out, which should cause zeroing all it's memory.