2017-03-01 5 views
1

Ich versuche, mit LLVM in Rust mit this crate arbeiten. Ich versuche, eine Codegeneratorstruktur zu erstellen, die den Kontext, das Modul und den Builder für mich enthält, aber wenn ich versuche, zu kompilieren, erhalte ich eine Fehlermeldung, die besagt: c does not live long enough. Wie kann ich das kompilieren lassen und warum lebe ich nicht lange genug?Wert nicht lang genug, wenn in struct

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, 
     } 
    } 
} 

Vollfehlermeldung:

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

Warum die downvote? – BookOwl

Antwort

2

Das sieht aus wie eine jener Situationen, in denen Lebenszeit elision Dinge weniger klar macht.

Hier ist der prototype von Builder::new:

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

die Sie vielleicht denken, dass die CSemiBox hat keine Beziehung auf die Lebensdauer von context. Aber die definition von CSemiBox hat eine Lebensdauer Parameter:

pub struct CSemiBox<'a, D> 

Wie ich es verstehe, wenn der Ausgabetyp einer Funktion (in diesem Fall Builder::new) ein Leben lang Parameter hat, kann es elided werden, wenn es nur ein eingegeben Lebenszeit. (Die Regeln für die Lebensdauer sind in the book und in this question beschrieben.) In diesem Fall wird die Lebensdauer der Ausgänge als gleich der Eingangslebensdauer angenommen. Das bedeutet, dass der Prototyp aus, bevor sie tatsächlich äquivalent zu den folgenden:

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

Ich hoffe, das klärt, was los ist: nach Builder::new(&c), die CSemiBox einen Verweis auf die Context enthält es aus erstellt wurde (b enthält einen Verweis auf c) . Sie können b und c nicht in dieselbe Struktur einfügen, da der Compiler in der Lage sein muss, zu beweisen, dass c überlebt. Für eine genauere Erklärung, siehe Why can't I store a value and a reference to that value in the same struct?

Es gibt zwei Möglichkeiten, wie ich damit umgehen kann. (Sie können nicht Rc verwenden, weil Sie nicht die Kiste steuern.)

  1. Speichern Sie nicht den Context innerhalb der CodeGen Struktur. Sie sind eingeschränkt in der Struktur Ihres Codes, aber das ist nicht unbedingt schlecht.

  2. Da die Context auf dem Heap gespeichert ist, können Sie unsafe verwenden, um die Referenzen (scheinen) eine 'static Lebensdauer zu haben. Etwas wie das folgende Snippet sollte funktionieren, das die lebenslange Annotation von CodeGen entfernt. Wenn Sie dies tun (wie immer Sie unsafe verwenden), übernehmen Sie die Verantwortung für die Sicherheit der exponierten Schnittstelle. Das heißt zum Beispiel, CodeGen kann keine Referenzen auf builder und module herausgeben, weil das einen 'static Verweis auf context ergeben könnte.

    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

[Siehe auch diese Frage.] (Http://stackoverflow.com/q/32300132/234590) –

+0

@ FrancisGagné AHA! Das ist der, mit dem ich verlinken wollte, aber ich konnte [den einen] finden (http://stackoverflow.com/questions/20698384/lifetime-of-rust-structs-that-reference-each-other), indem ich suche. Danke – trentcl

+0

Danke für die tolle Antwort! – BookOwl

Verwandte Themen