2017-03-01 9 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です:あなたはCSemiBoxcontextの寿命とは関係がないことを考えさせるかもしれません

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

。しかしCSemiBoxdefinitionは寿命パラメータを持っています

(この場合 Builder::newで)関数の出力タイプは寿命パラメータを持っている場合にのみ1つの入力があれば、それは省略されることができ、私はそれを理解したよう
pub struct CSemiBox<'a, D> 

、一生。 (ライフタイムのエリジョンのルールは、the bookthis questionに記載されています)。この場合、出力の有効期間は入力の有効期間と同じになります。それは前からのプロトタイプは次のように実際に同等であることを意味する:

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

私は、これは何が起こっているのか明確に願っています:Builder::new(&c)後、CSemiBoxは(bcへの参照を含む)から、それが作成されたContextへの参照が含まれています。コンパイラがcの寿命を証明することができなければならないので、bcを同じ構造体に入れることはできません。b。より詳しい説明はWhy can't I store a value and a reference to that value in the same struct?

これを処理する方法は2つあります。 (あなたが木箱をコントロールしていないので、あなたがRcを使用することはできません。)

  1. CodeGen構造体の内側Contextを保管しないでください。コードを構造化する方法は限られていますが、必ずしも悪いとは限りません。

  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

[この質問も参照してください](@stackoverflow.com/q/32300132/234590) –

+0

@FrancisGagnéAHA!それは私がリンクしたいものですが、私は[this one](http://stackoverflow.com/questions/20698384/lifetime-of-rust-structs-that-reference-each-other)を検索することでしか見つかりませんでした。ありがとう – trentcl

+0

すばらしい答えをありがとう! – BookOwl

関連する問題