Description
In rust borrowed constants have static lifetimes, even if the constants are simple literals in the middle of a function. For example, this compiles:
fn assert_static(_r: &'static u32) {}
fn main() {
assert_static(&1); // compiles
}
This works even in more involved situations, such as when the "literal" is a macro-generated array of structs whose fields are literals. (That's my actual use case, but I'll refer to the simple case of just having a u32
for simplicity.)
The problem is that it no longer works if the value is returned by a const fn
:
const fn inc(n: u32) -> u32 {
n + 1
}
fn assert_static(_r: &'static u32) {}
fn main() {
assert_static(&1);
assert_static(&inc(1)) // doesn't compile
}
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:9:20
|
9 | assert_static(&inc(1)) // doesn't compile
| ---------------^^^^^^-
| | |
| | creates a temporary which is freed while still in use
| argument requires that borrow lasts for `'static`
10 | }
I would expect (or rather wish) for the latter code to compile since the former did. Note that, since const
and static
are static
, it is possible to work around it by creating an explicit const
or static
inbetween. For example, all of these compile:
fn main() {
assert_static(&1);
{
const TMP: u32 = inc(1);
assert_static(&TMP);
}
{
static TMP: u32 = inc(1);
assert_static(&TMP);
}
assert_static({
const TMP: u32 = inc(1);
&TMP
});
assert_static({
static TMP: u32 = inc(1);
&TMP
});
}
While a workaround is available, it is not always obvious. Also it would be much nicer not to have to introduce all the temporary constants/statics, especially in code that calls several different const fns.
Activity
SkiFire13 commentedon Oct 28, 2021
This seems to be intended behaviour, see rust-lang/const-eval#19, RFC 3027 and the const-eval documentation on promotion
PatchMixolydic commentedon Oct 31, 2021
The
inline_const
feature gives a less noisy way to make this code compile (playground):RalfJung commentedon Nov 3, 2021
Indeed, this is expected behavior -- promoting
const fn
implicitly can lead to compile errors in code that really ought to compile, besides leading to nightmare consequences within rustc itself. The key difference between&1
and&const_fn()
is that the latter might panic or fail to evaluate for other reasons, so we cannot easily treat them the same.So I will close this issue; the intended convenient way to write such code in the future is via inline consts, tracked at #76001.
RalfJung commentedon Nov 3, 2021
Oh, also, a shameless plug: I have a little crate that partially implements inline consts as a macro -- https://crates.io/crates/inline-const.