Skip to content
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

uninitialized/zeroed statics/consts #411

Closed
Zoxc opened this Issue Oct 24, 2014 · 18 comments

Comments

Projects
None yet
10 participants
@Zoxc
Copy link

Zoxc commented Oct 24, 2014

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.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Oct 24, 2014

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.

@mahkoh

This comment has been minimized.

Copy link
Contributor

mahkoh commented Oct 24, 2014

Sounds like CTFE. See #322 for another proposal that suggested limited CTFE for intrinsic functions.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Oct 24, 2014

@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.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Oct 25, 2014

@arielb1 you can already do that, using uint::BYTES or uint::BITS.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Oct 25, 2014

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.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Oct 25, 2014

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.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Oct 25, 2014

@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.

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Oct 25, 2014

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.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Oct 25, 2014

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.

@gnzlbg

This comment has been minimized.

Copy link
Contributor

gnzlbg commented Feb 22, 2018

Would it be possible to make mem::uninitialized a const fn ? (or mem::zeroed?)

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Feb 22, 2018

@gnzlbg once rust-lang/rust#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
}
@gnzlbg

This comment has been minimized.

Copy link
Contributor

gnzlbg commented Mar 27, 2018

@oli-obk congrats on the merge of that PR :)

Any news about this? This issue comes up every now and then in stdsimd: rust-lang-nursery/stdsimd#403 (comment)

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Mar 27, 2018

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.

@derekdreery

This comment has been minimized.

Copy link

derekdreery commented Jun 10, 2018

@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?

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Jun 10, 2018

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

@RalfJung

This comment has been minimized.

Copy link
Member

RalfJung commented Jun 11, 2018

Seems like essentially a duplicate of rust-lang/rust#50150 to me.

Instead, we should strive to stabilize MaybeUninit and make it usable from const context.

@derekdreery

This comment has been minimized.

Copy link

derekdreery commented Jun 11, 2018

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?

@Centril

This comment has been minimized.

Copy link
Contributor

Centril commented Nov 27, 2018

Closing as ~"completed".

@Centril Centril closed this Nov 27, 2018

wycats pushed a commit to wycats/rust-rfcs that referenced this issue Mar 5, 2019

Merge pull request rust-lang#411 from SergeAstapov/master
Add Ember.js PR link for emberjs#337
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.