Value doesn't live long enough when put in struct - struct

I'm trying to work with LLVM in Rust using this crate. I'm trying to create a code generator struct to hold the context, module, and builder for me, but when I try to compile I get an error message that says c does not live long enough. How can I get this to compile, and why isn't c living long enough?
Code:
use llvm::*;
use llvm::Attribute::*;
pub struct CodeGen<'l> {
context: CBox<Context>,
builder: CSemiBox<'l, Builder>,
module: CSemiBox<'l, Module>,
}
impl<'l> CodeGen<'l> {
pub fn new() -> CodeGen<'l> {
let c = Context::new();
let b = Builder::new(&c);
let m = Module::new("test", &c);
CodeGen {
context: c,
builder: b,
module: m,
}
}
}
Full error message:
error: `c` does not live long enough
--> src/codegen.rs:17:31
|
17 | let b = Builder::new(&c);
| ^ does not live long enough
...
24 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'l as defined on the body at 15:32...
--> src/codegen.rs:15:33
|
15 | pub fn new() -> CodeGen<'l> {
| ^
error: `c` does not live long enough
--> src/codegen.rs:18:38
|
18 | let m = Module::new("test", &c);
| ^ does not live long enough
...
24 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'l as defined on the body at 15:32...
--> src/codegen.rs:15:33
|
15 | pub fn new() -> CodeGen<'l> {
| ^
error: aborting due to 2 previous errors

This looks like one of those situations where lifetime elision makes things less clear.
Here's the prototype of Builder::new:
pub fn new(context: &Context) -> CSemiBox<Builder>
Which might make you think that the CSemiBox doesn't have any relation to the lifetime of context. But the definition of CSemiBox has a lifetime parameter:
pub struct CSemiBox<'a, D>
As I understand it, when the output type of a function (in this case Builder::new) has a lifetime parameter, it can be elided if there is only one input lifetime. (The lifetime elision rules are described in the book and in this question.) In this case, the output lifetime is taken to be the same as the input lifetime. That means the prototype from before is actually equivalent to the following:
pub fn new<'a>(context: &'a Context) -> CSemiBox<'a, Builder>
I hope this clarifies what's happening: after Builder::new(&c), the CSemiBox contains a reference to the Context it was created from (b contains a reference to c). You can't put b and c in the same struct because the compiler has to be able to prove that c outlives b. For a more thorough explanation, see Why can't I store a value and a reference to that value in the same struct?
There are two ways I can think of to handle this. (You can't use Rc because you don't control the crate.)
Don't store the Context inside the CodeGen struct. You're limited in how you can structure your code, but that's not necessarily bad.
Since the Context is stored on the heap, you can use unsafe to make the references (appear to) have a 'static lifetime. Something like the following snippet ought to work, which removes the lifetime annotation from CodeGen. If you do this (as any time you use unsafe), you take responsibility for ensuring the safety of the exposed interface. That means, for example, CodeGen can't hand out references to builder and module, because that could leak a 'static reference to context.
pub struct CodeGen {
context: CBox<Context>,
builder: CSemiBox<'static, Builder>,
module: CSemiBox<'static, Module>,
}
impl CodeGen {
pub fn new() -> CodeGen {
let c = Context::new(); // returns a CBox<Context>
let c_static_ref: &'static _ = unsafe {
let c_ptr = c.as_ptr() as *const _; // get the underlying heap pointer
&*c_ptr
};
let b = Builder::new(c_static_ref);
let m = Module::new("test", c_static_ref);
CodeGen {
context: c,
builder: b,
module: m,
}
}
}

Related

"X does not live long enough" error when overriding struct field (that has the same lifetime as other fields) inside nested scope

I implemented a struct where I gave all reference fields the same lifetime. It seems like lifetimes don't work when I override field inside inner scope. I get an error:
error[E0597]: str2 does not live long enough
This is my code:
struct Test<'a> {
a: Option<&'a String>,
b: Option<&'a String>,
}
impl<'a> Test<'a> {
pub fn new(a: Option<&'a String>) -> Self {
Self {
a,
b: None,
}
}
}
fn main () {
let str1 = String::from("test1");
let mut test = Test::new(Some(&str1));
{
let str2 = String::from("test2");
test.b = Some(&str2);
}
println!("{:?} and {:?}", test.a, test.b);
}
This is minimal sandbox implementation.
Could you explain how to force references to work with a defined lifetime? And why doesn't the code compile in this case?
I think you misunderstand.
References with lifetime annotations don't keep values alive, they just specify how long they must be alive in order to be storable in the struct.
References do not take ownership of the variable. Lifetimes just ensure that whoever owns the variable does not destroy it before 'a is over.
The compiler automatically figures out what 'a must be. In your case, the latest point where test.a and test.b are getting used is the println!(...). Therefore the compiler determines that 'a of the test object must be a lifetime that is at least until the println!(...).
Then, the compiler realizes that the owner of test.b, which is str2, gets dropped at the end of the }, which does not match the lifetime 'a of the test object, as it doesn't reach the println!(...).
If you look at the more detailed error message of cargo, by running either cargo check, cargo build or cargo run, you can see just that:
error[E0597]: `str2` does not live long enough
--> src/main.rs:17:23
|
17 | test.b = Some(&str2);
| ^^^^^ borrowed value does not live long enough
18 | }
| - `str2` dropped here while still borrowed
19 |
20 | println!("{:?} and {:?}", test.a, test.b);
| ------ borrow later used here

Reference stored in Struct does not live long enough for closure

I'm holding a reference to a Struct inside another Struct, both of which are declared in the same block.
I later want to use the outer Struct in a closure which is run repeatedly and never returns.
The reference inside the Struct apparently does not live long enough, but in my understanding, it should never go out of scope, or at least should live at least as long as the Struct it is referring to:
struct MyStruct;
struct ReferenceStruct<'a> {
reference: &'a MyStruct
}
impl<'a> ReferenceStruct<'a> {
fn do_something(&self) -> () {}
}
fn run<F>(mut function: F) -> !
where
F: FnMut() -> () + 'static
{
loop {
function();
}
}
fn main() {
let my_struct = MyStruct;
let reference = ReferenceStruct { reference: &my_struct };
run(move || {
reference.do_something();
});
}
(link to playground)
The run function (for context) mirrors an event loop, similar to that of Winit, and in reality, I have another Struct which owns the value being referenced, but this example reproduces it in fewer lines.
The error:
error[E0597]: `my_struct` does not live long enough
--> src\main.rs:26:50
|
26 | let reference = ReferenceStruct { reference: &my_struct };
| ^^^^^^^^^^ borrowed value does not live long enough
27 |
28 | / run(move ||
29 | | {
30 | | reference.do_something();
31 | | });
| |______- argument requires that `my_struct` is borrowed for `'static`
32 | }
| - `my_struct` dropped here while still borrowed
It appears that my_struct is dropped at the end of main, but even if the program flow somehow escapes the loop, it surely lasts as long as the reference struct, which is as long as it needs to. I don't understand where or how this error could come about, or what to do about it.
Your problem is the lifetime bound 'static for the closure passed into run(). This means that the lifetime of reference is also 'static because it is moved into the closure, which in turn means that my_struct must also have static lifetime – and that is not the case.
Luckily, you do not need the 'static bound here. If you remove it, everything works:
...
fn run<F>(mut function: F) -> !
where
F: FnMut() -> ()
...
However, this might not be a solution in your use case if the event loop needs the closure to be 'static.

How does one restrict a lifetime to a closure environment in rust?

I am calling closures with a fold function inside another closure. While I am intending for nothing in this some_closure function to live outside the closure environment, I am receiving an error that I am dropping a value while it is still borrowed.
I have tried removing all lifetime specifiers from some_closure, because I find the compiler is much smarter than myself at figuring out lifetimes, but I'm also finding no success in this (the compiler will always ask for lifetime specifiers leading up to the point of the shown example).
What I would desire to do here is to specify a lifetime restricted to the length of the closure inside the function, rather than the function itself. But I have a feeling that what I think is the problem may not actually be my problem, and that there is some gap in my understanding of lifetimes in closures.
I've tried to minimize the example as much as possible:
struct HoldStr<'a>(&'a str);
fn clone_slice_borrows_into_vec<'a>() -> impl Fn(&[&'a HoldStr]) -> Vec<&'a HoldStr<'a>> {
|slice| {
let mut temp = vec![];
temp.clone_from_slice(slice);
temp
}
}
fn clone_slice_borrows_into_vec_same<'a>() -> impl Fn(&[&'a HoldStr]) -> Vec<&'a HoldStr<'a>> {
// Same as last function for the sake of example, but one can assume it does something else
}
fn some_closure<'a>() -> impl Fn() {
|| {
let my_vec = vec![HoldStr("one"), HoldStr("two")];
let my_vec_holding_borrow: Vec<&'a HoldStr> = my_vec.iter().collect();
let called_closures: [Box<dyn Fn(&[&'a HoldStr]) -> Vec<&'a HoldStr<'a>>>; 2] = [
Box::new(clone_slice_borrows_into_vec()),
Box::new(clone_slice_borrows_into_vec_same())
];
let _result = called_closures
.iter()
.fold(my_vec_holding_borrow, |acc, closure| closure(&acc));
}
}
I would expect everything to be dropped by the end of the closure inside some_closure and for this to be fine, especially since I am specifying that lifetime 'a does not relate to anything the function itself returns. But it seems that the borrowed value is expected to live until the end of the function itself. I get this error:
error[E0597]: `my_vec` does not live long enough
--> src/lib.rs:61:51
|
## | fn some_closure<'a>() -> impl Fn() {
| -- lifetime `'a` defined here
...
## | let my_vec_holding_borrow: Vec<&'a HoldStr> = my_vec.iter().collect();
| ---------------- ^^^^^^ borrowed value does not live long enough
| |
| type annotation requires that `my_vec` is borrowed for `'a`
...
## | }
| - `my_vec` dropped here while still borrowed
I'd be happy to hear anything from how to resolve the error, to that I've been going about this the wrong way in the first place.
You need higher-rank trait bounds for your closure types:
fn clone_slice_borrows_into_vec() -> impl for<'a> Fn(&[&'a HoldStr]) -> Vec<&'a HoldStr<'a>> {
...
(Full code in the playground)
The lifetime 'a isn't fixed for your closure. It should return a vector of references with lifetime 'a for any input slice with references of this lifetime. Your code used an externally fixed lifetime instead, which could be chosen by the caller of clone_slice_borrows_into_vec().
If you have a funciton definition like
fn foo<'a>() -> &'a Foo
then it's basically always a mistake. This lets the caller request an arbitrary lifetime, and the function promises to create a reference of this lifetime out of thin air, which is only possible if it gets static references from some global storage, in which case it should simply return &'static Foo.

Rust, how to return reference to something in a struct that lasts as long as the struct?

I am porting a compiler I wrote to Rust. In it, I have an enum Entity which represents things like functions and variables:
pub enum Entity<'a> {
Variable(VariableEntity),
Function(FunctionEntity<'a>)
// Room for more later.
}
I then have a struct Scope which is responsible for holding on to these entities in a hash map, where the key is the name given by the programmer to the entity. (For example, declaring a function named sin would put an Entity into the hash map at the key sin.)
pub struct Scope<'a> {
symbols: HashMap<String, Entity<'a>>,
parent: Option<&'a Scope<'a>>
}
I would like to be able to get read-only references to the objects in the HashMap so that I can refer to it from other data structures. For example, when I parse a function call, I want to be able to store a reference to the function that is being called instead of just storing the name of the function and having to look up the reference every time I need the actual Entity object corresponding to the name. To do so, I have made this method:
impl<'a> Scope<'a> {
pub fn lookup(&self, symbol: &str) -> Option<&'a Entity<'a>> {
let result = self.symbols.get(symbol);
match result {
Option::None => match self.parent {
Option::None => Option::None,
Option::Some(parent) => parent.lookup(symbol),
},
Option::Some(_value) => result
}
}
}
However, this results in a compilation error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/vague/scope.rs:29:31
|
29 | let result = self.symbols.get(symbol);
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 28:3...
--> src/vague/scope.rs:28:3
|
28 | / pub fn lookup(&self, symbol: &str) -> Option<&'a Entity<'a>> {
29 | | let result = self.symbols.get(symbol);
30 | | match result {
31 | | Option::None => match self.parent {
... |
36 | | }
37 | | }
| |___^
note: ...so that reference does not outlive borrowed content
--> src/vague/scope.rs:29:18
|
29 | let result = self.symbols.get(symbol);
| ^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 9:6...
--> src/vague/scope.rs:9:6
|
9 | impl<'a> Scope<'a> {
| ^^
= note: ...so that the expression is assignable:
expected std::option::Option<&'a vague::entity::Entity<'a>>
found std::option::Option<&vague::entity::Entity<'_>>
Things I Tried
There are several ways to make the compilation error go away, but none of them give the behavior I want. First, I can do this:
pub fn lookup(&self, symbol: &str) -> Option<&Entity<'a>> {
But this means the reference will not live long enough, so I can't put it into a struct or any other kind of storage that will outlive the scope that lookup is called from. Another solution was this:
pub fn lookup(&self, symbol: &str) -> Option<&'a Entity> {
Which I do not understand why it could compile. As part of the struct definition, things inside Entity objects in the hash map must live at least as long as the scope, so how can the compiler allow the return type to be missing that? Additionally, why would the addition of <'a> result in the previous compiler error, since the only place the function is getting Entitys from is from the hash map, which is defined as having a value type of Entity<'a>. Another bad fix I found was:
pub fn lookup(&'a self, symbol: &str) -> Option<&'a Entity<'a>> {
Which would mean that lookup can only be called once, which is obviously a problem. My previous understanding was incorrect, but the problem still remains that requiring the reference to self to have the same lifetime as the whole object severely restricts the code in that I can't call this method from a reference with any shorter lifetime, e.g. one passed in as a function argument or one created in a loop.
How can I go about fixing this? Is there some way I can fix the function as I have it now, or do I need to implement the behavior I'm looking for in an entirely different way?
Here's the signature you want:
pub fn lookup(&self, symbol: &str) -> Option<&'a Entity<'a>>
Here's why it can't work: it returns a reference that borrows an Entity for longer than lookup initially borrowed the Scope. This isn't illegal, but it means that the reference lookup returns can't be derived from the self reference. Why? Because given the above signature, this is valid code:
let sc = Scope { ... };
let foo = sc.lookup("foo");
drop(sc);
do_something_with(foo);
This code compiles because it has to: there is no lifetime constraint that the compiler could use to prove it wrong, because the lifetime of foo isn't coupled to the borrow of sc. But clearly, if lookup were implemented the way you first tried, foo would contain a dangling pointer after drop(sc), which is why the compiler rejected it.
You must redesign your data structures to make the given signature for lookup work. It's not clear how best to do this given the code in the question, but here are some ideas:
Decouple the lifetimes in Scope so that the parent is borrowed for a different lifetime than the symbols. Then have lookup take &'parent self. This probably will not work by itself, depending on what you need to do with the Entitys, but you may need to do it anyway if you need to distinguish between the lifetimes of different data.
pub struct Scope<'parent, 'sym> {
symbols: HashMap<String, Entity<'sym>>,
parent: Option<&'parent Scope<'parent, 'sym>>,
}
impl<'parent, 'sym> Scope<'parent, 'sym> {
pub fn lookup(&'parent self, symbol: &str) -> Option<&'parent Entity<'sym>> {
/* ... */
}
}
Store your Scopes and/or your Entitys in an arena. An arena can give out references that outlive the self-borrow, as long as they don't outlive the arena data structure itself. The tradeoff is that nothing in the arena will be deallocated until the whole arena is destroyed. It's not a substitute for garbage collection.
Use Rc or Arc to store your Scopes and/or your Entitys and/or whatever data Entity stores that contains references. This is one way to get rid of the lifetime parameter completely, but it comes with a small runtime cost.

Return type for rusqlite MappedRows

I am trying to write a method that returns a rusqlite::MappedRows:
pub fn dump<F>(&self) -> MappedRows<F>
where F: FnMut(&Row) -> DateTime<UTC>
{
let mut stmt =
self.conn.prepare("SELECT created_at FROM work ORDER BY created_at ASC").unwrap();
let c: F = |row: &Row| {
let created_at: DateTime<UTC> = row.get(0);
created_at
};
stmt.query_map(&[], c).unwrap()
}
I am getting stuck on a compiler error:
error[E0308]: mismatched types
--> src/main.rs:70:20
|
70 | let c: F = |row: &Row| {
| ____________________^ starting here...
71 | | let created_at: DateTime<UTC> = row.get(0);
72 | | created_at
73 | | };
| |_________^ ...ending here: expected type parameter, found closure
|
= note: expected type `F`
= note: found type `[closure#src/main.rs:70:20: 73:10]`
What am I doing wrong here?
I tried passing the closure directly to query_map but I get the same compiler error.
I'll divide the answer in two parts, the first about how to fix the return type without considering borrow-checker, the second about why it doesn't work even if you fixed the return type.
§1.
Every closure has a unique, anonymous type, so c cannot be of any type F the caller provides. That means this line will never compile:
let c: F = |row: &Row| { ... } // no, wrong, always.
Instead, the type should be propagated out from the dump function, i.e. something like:
// ↓ no generics
pub fn dump(&self) -> MappedRows<“type of that c”> {
..
}
Stable Rust does not provide a way to name that type. But we could do so in nightly with the "impl Trait" feature:
#![feature(conservative_impl_trait)]
// ↓~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn dump(&self) -> MappedRows<impl FnMut(&Row) -> DateTime<UTC>> {
..
}
// note: wrong, see §2.
The impl F here means that, “we are going to return a MappedRows<T> type where T: F, but we are not going to specify what exactly is T; the caller should be ready to treat anything satisfying F as a candidate of T”.
As your closure does not capture any variables, you could in fact turn c into a function. We could name a function pointer type, without needing "impl Trait".
// ↓~~~~~~~~~~~~~~~~~~~~~~~~
pub fn dump(&self) -> MappedRows<fn(&Row) -> DateTime<UTC>> {
let mut stmt = self.conn.prepare("SELECT created_at FROM work ORDER BY created_at ASC").unwrap();
fn c(row: &Row) -> DateTime<UTC> {
row.get(0)
}
stmt.query_map(&[], c as fn(&Row) -> DateTime<UTC>).unwrap()
}
// note: wrong, see §2.
Anyway, if we do use "impl Trait", since MappedRows is used as an Iterator, it is more appropriate to just say so:
#![feature(conservative_impl_trait)]
pub fn dump<'c>(&'c self) -> impl Iterator<Item = Result<DateTime<UTC>>> + 'c {
..
}
// note: wrong, see §2.
(without the 'c bounds the compiler will complain E0564, seems lifetime elision doesn't work with impl Trait yet)
If you are stuck with Stable Rust, you cannot use the "impl Trait" feature. You could wrap the trait object in a Box, at the cost of heap allocation and dynamic dispatch:
pub fn dump(&self) -> Box<Iterator<Item = Result<DateTime<UTC>>>> {
...
Box::new(stmt.query_map(&[], c).unwrap())
}
// note: wrong, see §2.
§2.
The above fix works if you want to, say, just return an independent closure or iterator. But it does not work if you return rusqlite::MappedRows. The compiler will not allow the above to work due to lifetime issue:
error: `stmt` does not live long enough
--> 1.rs:23:9
|
23 | stmt.query_map(&[], c).unwrap()
| ^^^^ does not live long enough
24 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 15:80...
--> 1.rs:15:81
|
15 | pub fn dump(conn: &Connection) -> MappedRows<impl FnMut(&Row) -> DateTime<UTC>> {
| ^
And this is correct. MappedRows<F> is actually MappedRows<'stmt, F>, this type is valid only when the original SQLite statement object (having 'stmt lifetime) outlives it — thus the compiler complains that stmt is dead when you return the function.
Indeed, if the statement is dropped before we iterate on those rows, we will get garbage results. Bad!
What we need to do is to make sure all rows are read before dropping the statement.
You could collect the rows into a vector, thus disassociating the result from the statement, at the cost of storing everything in memory:
// ↓~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn dump(&self) -> Vec<Result<DateTime<UTC>>> {
..
let it = stmt.query_map(&[], c).unwrap();
it.collect()
}
Or invert the control, let dump accept a function, which dump will call while keeping stmt alive, at the cost of making the calling syntax weird:
// ↓~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pub fn dump<F>(&self, mut f: F) where F: FnMut(Result<DateTime<UTC>>) {
...
for res in stmt.query_map(&[], c).unwrap() {
f(res);
}
}
x.dump(|res| println!("{:?}", res));
Or split dump into two functions, and let the caller keep the statement alive, at the cost of exposing an intermediate construct to the user:
#![feature(conservative_impl_trait)]
pub fn create_dump_statement(&self) -> Statement {
self.conn.prepare("SELECT '2017-03-01 12:34:56'").unwrap()
}
pub fn dump<'s>(&self, stmt: &'s mut Statement) -> impl Iterator<Item = Result<DateTime<UTC>>> + 's {
stmt.query_map(&[], |row| row.get(0)).unwrap()
}
...
let mut stmt = x.create_dump_statement();
for res in x.dump(&mut stmt) {
println!("{:?}", res);
}
The issue here is that you are implicitly trying to return a closure, so to find explanations and examples you can search for that.
The use of the generic <F> means that the caller decides the concrete type of F and not the function dump.
What you would like to achieve instead requires the long awaited feature impl trait.

Resources