# Allow non-const statics?

**URL:** <https://internals.rust-lang.org/t/allow-non-const-statics/10676>\
**Category:** language design\
**Created:** [August 8, 2019, 5:28pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676 "2019-08-08T17:28:15Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![axos88](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/axos88/32/5927_2.png) [@axos88](https://internals.rust-lang.org/u/axos88)\
**Post date:** [August 8, 2019, 5:28pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/1 "2019-08-08T17:28:16Z")

</div>

Waking up [https://github.com/rust-lang/rfcs/issues/1898](https://github.com/rust-lang/rfcs/issues/1898)

I'm working on a no\_std application, WITHOUT atomics, becuase my processor doesn't support the necessary instructions for that. (thumbv6-m, cortex-m0, no strex, ldrex instructions). It can be emulated by disabling interrupts, but that doesn't magically make `core::sync` or `core::atomics` to be compiled in.

This makes `lazy_static!` unavailable because it relies on `core::atomics` (compare\_and\_swap).

So basically I can't have static variables that are not const, but some of my statics (such as creating a freertos mutex, which calls into C code using FFI) cannot be made const, and I highly doubt FFI will ever be const, especially since it includes heap allocation for the FreeRTOS mutex object

I also propose the ability to create static variables that are initialized when starting up the application. In embedded space, this is requires additional discussion, since we need to pick an place when the statics' initialization will take place. The user needs to be able to inject code before that happens to initialize the RAM controller for example, and to set up the stack. Perhaps a special function could be generated that deals with this, and the user would be responsible to call that at the correct time.

I haven't done the math, but I would suspect the compiler could perhaps create a dependency graph of which non-const static refers to which another one, and initialize them in the correct order.

This would make lazy\_static mostly obsolete, because in many cases lazy\_static is not used for lazy initialization, but rather to circumvent this limitation of static variables, thus it's used to initialize "stuff" before first use, and the requirement is only that, and it is not necessary for it to happen as late as possible.

Before investing more effort on this, I'd like to hear your thoughts, and perhaps I can make an RFC out of this if there seems to be a general opinion that it's worth exploring.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [August 8, 2019, 5:57pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/2 "2019-08-08T17:57:02Z")

</div>

> [@axos88](#):
>
> I also propose the ability to create static variables that are initialized when starting up the application.

This is "life before main", which Rust has been trying to avoid. See previous conversations like

> [@Pre-RFC: Add language support for global constructor functions](https://internals.rust-lang.org/t/pre-rfc-add-language-support-for-global-constructor-functions/9840):
>
> Hi! I've written up a WIP RFC for adding global constructors, otherwise known as ctors or static initializers. Crates like [typetag](https://github.com/dtolnay/typetag) currently use these constructors, but only support our tier-1 platforms because they depend on rust-ctor. By adding compiler support, we could expand this to all platforms. If anyone could give feedback, either to the wording or the ideas, it would be greatly appreciated! I've tried to fill in as much detail as I can, but it's fairly unrefined. I plan on refining …

The latest direction I remember here is people trying to find a way to meet the main needs without getting problems, such as getting a list of all \_\_\_\_\_\_s from multiple crates.

---

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [August 8, 2019, 7:28pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/3 "2019-08-08T19:28:49Z")

</div>

Does `static mut` not suffice for your case? It's unsafe (for obvious reasons) but certainly possible today.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [August 8, 2019, 9:25pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/4 "2019-08-08T21:25:50Z")

</div>

First what you can do is emulate `std::sync::Once` with whatever means that you have, just enough to do `Once::call_once`

Then you can do

```rust
fn get_global() -> &'static T {
    fn init() -> T { ... }
    
    use std::mem::MaybeUninit;
    
    static mut GLOBAL: MaybeUninit<T> = MaybeUninit::uninit();
    static mut ONCE: Once = Once::new();
    
    unsafe {
        ONCE.call_once(|| GLOBAL = MaybeUninit(init()));
        
        &*GLOBAL.as_ptr()
    }
}

```

---

<div class="post-metadata">

**Author:** ![bill\_myers](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bill_myers/32/4085_2.png) [@bill\_myers](https://internals.rust-lang.org/u/bill_myers)\
**Post date:** [August 9, 2019, 12:12am UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/5 "2019-08-09T00:12:53Z")

</div>

It's impossible to determine precisely which non-const static refers to which other one due to trait object indirection, as well as this fact becoming an hidden part of the API of all functions.

The proper solution to your problem is to provide atomics for your platform and use lazy\_static, either by disallowing multithreading and using non-atomic instructions, disabling interrupts if you have the privilege for that or by using a kernel-based solution (if a context switch happens in the middle of an "atomic", emulate it in-kernel before switching).

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [August 9, 2019, 2:13am UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/6 "2019-08-09T02:13:11Z")

</div>

> [@axos88](#):
>
> I haven't done the math, but I would suspect the compiler could perhaps create a dependency graph of which non-const static refers to which another one, and initialize them in the correct order.

FWIW, Go is the only language I know of with a principled approach to this, and it already has to do a lot of work to allow this, and vastly restricts the type of initialization allowed in global `var`s.

> [@bill\_myers](#):
>
> It's impossible to determine precisely which non-const static refers to which other one due to trait object indirection, as well as this fact becoming an hidden part of the API of all functions.

Not necessarily. One could imagine each (non trivially initialized) static being paired with some "initialized" flag; the functions in the `.init` list return immediately if said flag is set, and the `.init` list is iterated over and each hook is called as normal before main.

Of course, now every access of a non-const static must be lowered to something like

```rust
  movb FOO_flag, %al
  test %al, %al
  jnz read
  call FOO_init
  movb $1, %al,
  movb %al, FOO_flag ; (*)
.read:
  mov FOO, %rax

```

If we assume `.init` functions are all called sequentially on a single thread, there is no need to worry about atomic access for `(*)`. Of course, we would also need to make `thread::spawn()` panic if called before main to avoid shenanigans... and we probably want to make panics abort if called before main because, again, shenanigans. Also, we can't expose these symbols to C because they have a wacky calling convention...

...this seems like more trouble than its worth, really.

---

<div class="post-metadata">

**Author:** ![axos88](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/axos88/32/5927_2.png) [@axos88](https://internals.rust-lang.org/u/axos88)\
**Post date:** [August 9, 2019, 5:40am UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/7 "2019-08-09T05:40:40Z")

</div>

> [@bascule](#):
>
> Does `static mut` not suffice for your case? It's unsafe (for obvious reasons) but certainly possible today.

Yeah, that's what I wound up using for now, however that requires wrapping the whole thing in an Option, to be able to set a None value at compile time, meaning extra memory and CPU cycles for each access to unwrap it.

Umm... How do I quote multiple people?

> The proper solution to your problem is to provide atomics for your platform and use lazy\_static, either by disallowing multithreading and using non-atomic instructions, disabling interrupts if you have the privilege for that or by using a kernel-based solution

Yeah, for this particular case that would work, although I am unsure how to provide atomics for a target that does not define the necessary features. I did provide a hackyatomics::alloc::sync and hackyatomics::core::sync module that define them, but i'd need to modify every crate to support that - I did get a tip on that in another thread: [Adding stuff to a particular existing crate? #63231 - #2 by Amanieu](https://internals.rust-lang.org/t/adding-stuff-to-a-particular-existing-crate-63231/10677/2)

But this keeps happening with me more often than not, and providing a

```rust
  static FOO: Mutex<Peripheral> = Mutex::new(Peripheral::at(0x40008000))

```

Seems like a natural thing to do, but it's not.

> If we assume `.init` functions are all called sequentially on a single thread, there is no need to worry about atomic access for `(*)` . Of course, we would also need to make `thread::spawn()` panic if called before main to avoid shenanigans... and we probably want to make panics abort if called before main because, again, shenanigans. Also, we can't expose these symbols to C because they have a wacky calling convention...

I see where you are going with this. And this still seems doable, but thread::spawn() is not necessarily the only way to spawn a new thread. The compiler cannot enforce that somebody doesn't access libpthread directly. Especially in case of embedded applications, where the kernel is compiled into the app as a module (such as my own case) creating new tasks / threads is basically calling random functions. But we could just push this responsibility onto the user, by saying it's UB to spawn new threads from the initialization functions. I'm not sure I follow why these statics would be a problem to export over FFI though. Before the initializers run, they would be unitialized memory area, after the initializers run they would be just normal pointers to the data. The initialization code could push one bit per static to be initialized onto the stack, and set the intialized flags there --- ooh I see what you mean. During initialization the flags need to be checked, so basically they need to be checked at every access. nope, that's not good indeed.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [August 9, 2019, 9:11am UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/8 "2019-08-09T09:11:00Z")

</div>

> [@axos88](#):
>
> This makes `lazy_static!` unavailable because it relies on `core::atomics` (compare\_and\_swap

> [@https://docs.rs/lazy\_static/1.3.0/lazy\_static/#cargo-features](#):
>
> # [Cargo features](https://docs.rs/lazy_static/1.3.0/lazy_static/#cargo-features)
> 
> This crate provides two cargo features:
> 
> - `spin_no_std` : This allows using this crate in a no-std environment, by depending on the standalone `spin` crate.

This would be equivalent to @RustyYato's solution but based on [`::spin::Once`](https://docs.rs/spin/0.5.1/spin/struct.Once.html) rather than [`::std::sync::Once`](https://doc.rust-lang.org/std/sync/struct.Once.html) so that it works in a `no_std` environment.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [August 9, 2019, 9:12am UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/9 "2019-08-09T09:12:58Z")

</div>

A spin lock where you might access it from an interrupt is a guaranteed deadlock.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [August 9, 2019, 9:17am UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/10 "2019-08-09T09:17:05Z")

</div>

If you can't use synchronisation then the API needs to be `unsafe` (at least the initialization part), based on a `static RacyUnsafeCell`

---

<div class="post-metadata">

**Author:** ![axos88](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/axos88/32/5927_2.png) [@axos88](https://internals.rust-lang.org/u/axos88)\
**Post date:** [August 9, 2019, 9:54am UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/11 "2019-08-09T09:54:36Z")

</div>

spin\_no\_std requires atomics - that's the issue.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [August 9, 2019, 2:54pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/12 "2019-08-09T14:54:01Z")

</div>

[`once_cell::unsync::Lazy`](https://docs.rs/once_cell/0.2.6/once_cell/unsync/struct.Lazy.html) provides non-syncronyzed initialize-on-first-use semantics. It shouldn't be too difficult to adjust it to an `unsafe` version that requires manual initialization early in `main`.

It'd basically be

```rust
static mut thing: _ = MaybeUninit::uninit();
fn get_thing() -> &_ {
    unsafe { thing.get_ref() }
}
fn set_thing() {
    unsafe { thing.write(compute_thing()) };
}

```

which then has the requirement that `set_thing` is called before `get_thing`. It's of course unsafe to set this up unless you mark `get_thing` unsafe. I don't think there's a way to actually wrap this up in a safe API.

The safe version is to initialize all the things in `main` then pass around a context struct that allows access to all the things. Init-once without synchronization and globally visible is possible but very unsafe.

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [August 9, 2019, 11:39pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/13 "2019-08-09T23:39:35Z")

</div>

> [@axos88](#):
>
> But we could just push this responsibility onto the user, by saying it's UB to spawn new threads from the initialization functions.

To be clear, this is my intended semantics. AFAIK there is no observeable way to spawn threads in safe Rust without going through thread::spawn.

> [@axos88](#):
>
> so basically they need to be checked at every access.

"need" is a strong word. I suspect that you can go a long way to proving (in the absence of erased vtables) that a particular guard is unnecessary.

That said, I think there is an alternative that is far simpler: declare this an advanced, unsafe feature, require spelling it `static X: T = unsafe { .. };`, and declare it UB to do _anything_ you can't guarantee doesn't access any other premain statics. Given the sorts of things one would want such a feature for, this sort of draconian restriction is totally reasonable.

Alternate syntax of `unsafe static X: T = ..;` is not unreasonable.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [August 10, 2019, 12:27pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/14 "2019-08-10T12:27:37Z")

</div>

Here is the kind of usage that you can have, which is not "too dangerous":

```rust
manually_init_static! {
    static FOO: i32 = {
        eprintln!(" FOO.init();");
        42
    };
}

fn main ()
{
    eprintln!("fn main ()\n{{");
    unsafe {
        // # Safety
        //
        // - Not yet multithreaded, so there cannot be parallel calls to .get()
        FOO.init();
    }
    ::crossbeam::thread::scope(|scope| (0 .. 10).for_each(|_| {
        scope.spawn(|_| {
            eprintln!(
                " <{:02?}> FOO = {:?}",
                ::std::thread::current().id(),
                FOO.get(),
            );
        });
    })).expect("Some thread panicked");
    eprintln!("}}");
}

```

For the full API and implementation, see:

- [the Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=23107d82e1f42ac7329eb0a4934e7d1a)

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [August 10, 2019, 4:45pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/15 "2019-08-10T16:45:01Z")

</div>

Your implementation assumes TLS, and I'd be shocked if the platform in question supports that in any reasonable way.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [August 10, 2019, 5:44pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/16 "2019-08-10T17:44:03Z")

</div>

These can be removed with an additional `# Safety` requirement on `.init()` against reentrancy; I just didn't want to think about reentrancy too hard.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [November 8, 2019, 5:56pm UTC](https://internals.rust-lang.org/t/allow-non-const-statics/10676/17 "2019-11-08T17:56:54Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
