我正在尝试使用 Rust 中的 LLVM这个板条箱。我正在尝试创建一个代码生成器结构来为我保存上下文、模块和构建器,但是当我尝试编译时,我收到一条错误消息:c does not live long enough
。我怎样才能编译它,为什么 c 的寿命还不够长?
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,
}
}
}
完整错误消息:
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
这看起来像是生命周期省略使事情变得不那么清晰的情况之一。
这是原型 of Builder::new
:
pub fn new(context: &Context) -> CSemiBox<Builder>
这可能会让你认为CSemiBox
与生命周期没有任何关系context
。但是定义 of CSemiBox
有一个生命周期参数:
pub struct CSemiBox<'a, D>
据我了解,当函数的输出类型(在本例中)Builder::new
) 有一个生命周期参数,如果只有一个输入生命周期,则可以省略该参数。 (生命周期省略规则描述于the book and in 这个问题.) 在这种情况下,输出寿命被认为与输入寿命相同。这意味着之前的原型实际上相当于以下内容:
pub fn new<'a>(context: &'a Context) -> CSemiBox<'a, Builder>
我希望这能澄清发生的事情:之后Builder::new(&c)
, the CSemiBox
包含对Context
它是从 (b
包含对c
)。你不能把b
and c
在同一个结构中,因为编译器必须能够证明c
比寿命长b
。有关更彻底的解释,请参阅为什么我不能在同一结构中存储值和对该值的引用?
我可以想到两种方法来处理这个问题。 (你不能使用Rc
因为你无法控制箱子。)
不要存储Context
在 - 的里面CodeGen
结构。您构建代码的方式受到限制,但这并不一定是坏事。
-
自从Context
存储在堆上,您可以使用unsafe
使参考文献(看起来)具有'static
寿命。像下面的代码片段这样的东西应该可以工作,它将生命周期注释从CodeGen
。如果你这样做(就像任何时候你使用unsafe
), 您负责确保暴露接口的安全。这意味着,例如,CodeGen
无法提供参考资料builder
and module
,因为这可能会泄漏'static
参考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,
}
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)