With the following code Snipet, I get an error when referencing CONST_VALUE_ERR_2.
Is this behaviour expected / documented, or is it a bug?
struct Foo<T>
{
value : T
}
impl<T> Foo<T> {
const fn new(value: T) -> Self {
Self { value }
}
}
fn get_foo<T>(_obj : &'static Foo<T>){
//use as &static Reference Foo
}
const CONST_VALUE_OK_1 : Foo<Option<Box<u32>>> = Foo{ value : None};
const CONST_VALUE_ERR_2 : Foo<Option<Box<u32>>> = Foo::new(None);
const CONST_VALUE_OK_3 : Foo<Option<u32>> = Foo{ value : None};
const CONST_VALUE_OK_4 : Foo<Option<u32>> = Foo::new(None);
fn main(){
get_foo(&CONST_VALUE_OK_1);
get_foo(&CONST_VALUE_ERR_2); // compiler error: temporary value dropped while borrowed
// creates a temporary value which is freed while still in use
// temporary value is freed at the end of this statement
// argument requires that borrow lasts for `'static`
get_foo(&CONST_VALUE_OK_3);
get_foo(&CONST_VALUE_OK_4);
}
It looks like the compiler is copying the expression assigned to the const variable when a box is in the generic?
get_foo(&Foo::<Option<Box<u32>>>{ value : None}); //ok
get_foo(&Foo::<Option<Box<u32>>>::new(None)); //same error
get_foo(&Foo::<Option<u32>>::new(None)); //is also an error, but
get_foo(&CONST_VALUE_OK_4); //was ok?
The difference is that the working ones get const promoted.
That is, the promoted expression can be evaluated at compile-time and the resulting value does not contain interior mutability or destructors (these properties are determined based on the value where possible, e.g. &None always has the type &'static Option<_>, as it contains nothing disallowed).
The details are unclear, but it's apparent that rustc has decided that a function call that produces a type with a destructor isn't const promoted.
I think this one is just from new being called in a non-const context, so it never gets const promoted.
More thoughts on the original thing: a reason why Rust wouldn't allow get_foo(&CONST_VALUE_ERR_2); is that Foo::new could produce an actual droppable value. Not Box, but there are droppable types that don't heap allocate. And this upholds the rule of Rust that as long as the function signature stays the same, changing the contents of the function can't cause uses of the function to stop compiling.