I am trying to implement an LLVM IR parser / CFG formation algorithm for a class project. The last time I did a compiler, I did my AST using enums, so I decided to try using trait objects this time. Here is my code: Rust Playground. 'a
is intended to represent the lifetime of the program &str
I pass into the analysis.
The error:
error[E0597]: `*op` does not live long enough
--> src/main.rs:79:35
|
78 | LabelOrInstr::Instr(op) => {
| -- binding `op` declared here
79 | let targets = op.targets();
| ^^ borrowed value does not live long enough
...
86 | edges.push(match target {
| ----- borrow later used here
...
94 | }
| - `*op` dropped here while still borrowed
I am trying to understand why op
is still borrowed. In my mind, op.targets()
returns tuples of owned Labels
that contain references to the program string. But the program string is not owned by op
, it is owned by main()
, so those references should be valid after op
gets dropped. I even tried to indicate this in my LabelOrInstr
and BasicBlock
, by saying that the trait object dyn Op<'a> + 'b
points to something which contains a reference valid for 'a
, the trait object itself is valid for 'b
, and 'a
must outlive 'b
, i.e., the program string outlives the trait object. When I then try to say that the items in edges
contain data valid for 'a
by changing line 62 to be Vec<(Label<'a>, Label<'a>)>
, I get the following error in addition:
error: lifetime may not live long enough
--> src/main.rs:48:24
|
44 | impl<'a: 'b, 'b> TryFrom<Function<'a, 'b>> for ControlFlowGraph<'a, 'b> {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
48 | let mut edges: Vec<(Label<'a>, Label<'a>)> = Vec::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
I could just abandon this way and try something else, but I really want to understand what's going on here or what I am misunderstanding.