2017-03-01 53 views
1

我試圖使用this crate在Rust中使用LLVM。我試圖創建一個代碼生成器結構來爲我保存上下文,模塊和生成器,但是當我嘗試編譯時,我收到一條錯誤消息,指出c does not live long enough。我怎樣才能把它編譯出來,爲什麼c不夠長?價值不夠長時,放在結構中

代碼:

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 
+0

爲什麼downvote? – BookOwl

回答

2

這看起來像在哪裏一輩子省音使事情不太清楚這些情況之一。

這裏是Builder::newprototype

pub fn new(context: &Context) -> CSemiBox<Builder> 

這可能會讓你覺得CSemiBox沒有任何關係的context壽命。但CSemiBoxdefinition具有壽命參數:

pub struct CSemiBox<'a, D> 

據我所知,當一個函數的輸出類型(在這種情況下Builder::new)具有壽命參數,它可以如果只有一個輸入被消隱一生。 (生命週期規則在the bookthis question中描述。)在這種情況下,輸出壽命與輸入壽命相同。這意味着,從之前的原型實際上是等同於以下:

pub fn new<'a>(context: &'a Context) -> CSemiBox<'a, Builder> 

我希望這個澄清發生的事情:Builder::new(&c)之後,CSemiBox包含它從創建Context參考(b包含c參考) 。您不能將bc放在同一個結構中,因爲編譯器必須能夠證明c超出b。有關更詳盡的解釋,請參閱Why can't I store a value and a reference to that value in the same struct?

有兩種方法可以考慮處理此問題。 (您不能使用Rc因爲你不控制箱。)

  1. 不要Context存儲CodeGen結構內。您在構建代碼的方式方面有限,但這並不一定是錯誤的。

  2. 由於Context存儲在堆中,因此可以使用unsafe使引用(似乎)具有'static的生存期。像下面的代碼片段應該工作,從CodeGen刪除生命週期註釋。如果你這樣做(任何時候你使用unsafe),你負責確保暴露接口的安全。這意味着,例如,CodeGen不能發出對buildermodule的引用,因爲這可能會將'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, 
         } 
        } 
    } 
    
+2

[另請參閱此問題。](http://stackoverflow.com/q/32300132/234590) –

+0

@FrancisGagnéAHA!這是我想鏈接到,但我只能通過搜索找到[這一個](http://stackoverflow.com/questions/20698384/lifetime-of-rust-structs-that-reference-each-other)。謝謝 – trentcl

+0

謝謝你的偉大答案! – BookOwl