Change localized statics in generics to be unique to the complete codegen for a generic.
At the moment the following code will only have one static for all the instantions of the function.
fn foo<T>() {
static local_foo : u32 = 0;
}
This is not what I would expect. I would expect foo::<u8> and foo::<u16> would generate different local_foo's. This would allow for the case of Self to be used in a static call as a generic argument like so.
Well, this would be a breaking change for existing code, so it would need a transition plan or an opt-in.
Note that right now it's the rule that -- other than visibility -- there's no difference for where you put an item (fn/struct/impl/const/static/...). If it's inside or outside a fn, it works exactly the same. That's why you can't do something like fn Foo<T>() { static FOO: Option<T> = None; } either.
Another thing is that generic functions can ne duplicated (and meed to if they are instantiated within multiple crates), but statics are defined as having a single address, which would be impossible for generic statics, even for a single instantiation. If I were to use the same A<u8> static within two crates, both would need to define a symbol for it. If this symbol were to be public, it would result in a conflicting definition and thus linker error, if it were local, you would get two copies.
I agree that we shouldn't change the existing behavior, as it would break existing semantics. I do think, though, we should have a simple syntax for "give me a different one of these for each generic instantiation", or "... for each generic instantiation of this subset of parameters". (Even if the type of the static isn't actually generic.)
I think that should only be allowed if there is no interior mutability as rustc is free to instantiate generics multiple times. It has to cross-crate and often does inside the same crate for each cgu that uses it. Currently cgu splitting splits at the module boundary, but this is not guaranteed. Allowing interior mutability with generic statics would make it way too easy to accidentally depend on a specific cgu splitting method IMHO.
In my honest opinion this breaks encapsulation. I would expect it to print 0 for each. I would be willing to entertain like a keyword or a context dependent modifier.
error[E0412]: cannot find type `T` in this scope
--> src/lib.rs:7:39
|
5 | impl Foo {
| - help: you might be missing a type parameter: `<T>`
6 | fn get_name()->&'static str {
7 | const { std::any::type_name::<T>() }
| ^ not found in this scope
warning: the feature `inline_const` is incomplete and may not be safe to use and/or cause compiler crashes
--> src/lib.rs:1:12
|
1 | #![feature(inline_const)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
error: internal compiler error: compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs:374:17: cannot relate region: LUB(ReStatic, ReErased)
thread 'rustc' panicked at 'Box<dyn Any>', compiler/rustc_errors/src/lib.rs:1147:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md
note: rustc 1.58.0-nightly (46b8e7488 2021-11-07) running on x86_64-unknown-linux-gnu
note: compiler flags: -C embed-bitcode=no -C codegen-units=1 -C debuginfo=2 --crate-type lib
note: some of the compiler flags provided by cargo are hidden
query stack during panic:
#0 [typeck] type-checking `<impl at src/lib.rs:5:1: 9:2>::get_name`
#1 [typeck_item_bodies] type-checking all item bodies
end of query stack
For more information about this error, try `rustc --explain E0412`.
warning: `playground` (lib) generated 1 warning
error: could not compile `playground` due to previous error; 1 warning emitted
Edit:
Needed to do the following I think, but I am getting a timeout. Not sure if it is a playground issue or an infinite loop.
error[E0401]: can't use generic parameters from outer function
If it did compile I would expect it to print 0, 0, 0. I don't necessarily think it should compile (because the difference between Foo<i32> ⇒ all instantiations share a static and Foo<T> ⇒ each generic instantiation gets its own static is a fairly small edit distance for a fairly large effect.). But a noisier syntax would make sense if it happens at all.
AFAIK this is not possible with dylib crates on windows, since when the complete set of instantiations of the static can be known it's no longer possible to merge them.