diff --git a/src/librustc/middle/borrowck/doc.rs b/src/librustc/middle/borrowck/doc.rs index ffc269f8cc8..e8753a9726d 100644 --- a/src/librustc/middle/borrowck/doc.rs +++ b/src/librustc/middle/borrowck/doc.rs @@ -56,26 +56,34 @@ it is safe with respect to the in-scope loans. Throughout the docs we'll consider a simple subset of Rust in which you can only borrow from lvalues, defined like so: - LV = x | LV.f | *LV +```notrust +LV = x | LV.f | *LV +``` Here `x` represents some variable, `LV.f` is a field reference, and `*LV` is a pointer dereference. There is no auto-deref or other niceties. This means that if you have a type like: - struct S { f: uint } +```notrust +struct S { f: uint } +``` and a variable `a: ~S`, then the rust expression `a.f` would correspond to an `LV` of `(*a).f`. Here is the formal grammar for the types we'll consider: - TY = () | S<'LT...> | ~TY | & 'LT MQ TY | @ MQ TY - MQ = mut | imm | const +```notrust +TY = () | S<'LT...> | ~TY | & 'LT MQ TY | @ MQ TY +MQ = mut | imm | const +``` Most of these types should be pretty self explanatory. Here `S` is a struct name and we assume structs are declared like so: - SD = struct S<'LT...> { (f: TY)... } +```notrust +SD = struct S<'LT...> { (f: TY)... } +``` # Borrowing and loans @@ -85,13 +93,15 @@ struct name and we assume structs are declared like so: Now, imagine we had a program like this: - struct Foo { f: uint, g: uint } - ... - 'a: { - let mut x: ~Foo = ...; - let y = &mut (*x).f; - x = ...; - } +```notrust +struct Foo { f: uint, g: uint } +... +'a: { + let mut x: ~Foo = ...; + let y = &mut (*x).f; + x = ...; +} +``` This is of course dangerous because mutating `x` will free the old value and hence invalidate `y`. The borrow checker aims to prevent @@ -108,9 +118,11 @@ the borrow, and (3) a set of restrictions. In the code, `Loan` is a struct defined in `middle::borrowck`. Formally, we define `LOAN` as follows: - LOAN = (LV, LT, MQ, RESTRICTION*) - RESTRICTION = (LV, ACTION*) - ACTION = MUTATE | CLAIM | FREEZE +```notrust +LOAN = (LV, LT, MQ, RESTRICTION*) +RESTRICTION = (LV, ACTION*) +ACTION = MUTATE | CLAIM | FREEZE +``` Here the `LOAN` tuple defines the lvalue `LV` being borrowed; the lifetime `LT` of that borrow; the mutability `MQ` of the borrow; and a @@ -139,10 +151,12 @@ To give you a better feeling for what kind of restrictions derived from a loan, let's look at the loan `L` that would be issued as a result of the borrow `&mut (*x).f` in the example above: - L = ((*x).f, 'a, mut, RS) where - RS = [((*x).f, [MUTATE, CLAIM, FREEZE]), - (*x, [MUTATE, CLAIM, FREEZE]), - (x, [MUTATE, CLAIM, FREEZE])] +```notrust +L = ((*x).f, 'a, mut, RS) where + RS = [((*x).f, [MUTATE, CLAIM, FREEZE]), + (*x, [MUTATE, CLAIM, FREEZE]), + (x, [MUTATE, CLAIM, FREEZE])] +``` The loan states that the expression `(*x).f` has been loaned as mutable for the lifetime `'a`. Because the loan is mutable, that means @@ -200,10 +214,12 @@ conditions that it uses. For simplicity I will ignore const loans. I will present the rules in a modified form of standard inference rules, which looks as as follows: - PREDICATE(X, Y, Z) // Rule-Name - Condition 1 - Condition 2 - Condition 3 +```notrust +PREDICATE(X, Y, Z) // Rule-Name + Condition 1 + Condition 2 + Condition 3 +``` The initial line states the predicate that is to be satisfied. The indented lines indicate the conditions that must be met for the @@ -274,12 +290,14 @@ Let's begin with the rules for variables, which state that if a variable is declared as mutable, it may be borrowed any which way, but otherwise the variable must be borrowed as immutable or const: - MUTABILITY(X, MQ) // M-Var-Mut - DECL(X) = mut +```notrust +MUTABILITY(X, MQ) // M-Var-Mut + DECL(X) = mut - MUTABILITY(X, MQ) // M-Var-Imm - DECL(X) = imm - MQ = imm | const +MUTABILITY(X, MQ) // M-Var-Imm + DECL(X) = imm + MQ = imm | const +``` ### Checking mutability of owned content @@ -287,32 +305,38 @@ Fields and owned pointers inherit their mutability from their base expressions, so both of their rules basically delegate the check to the base expression `LV`: - MUTABILITY(LV.f, MQ) // M-Field - MUTABILITY(LV, MQ) +```notrust +MUTABILITY(LV.f, MQ) // M-Field + MUTABILITY(LV, MQ) - MUTABILITY(*LV, MQ) // M-Deref-Unique - TYPE(LV) = ~Ty - MUTABILITY(LV, MQ) +MUTABILITY(*LV, MQ) // M-Deref-Unique + TYPE(LV) = ~Ty + MUTABILITY(LV, MQ) +``` ### Checking mutability of immutable pointer types Immutable pointer types like `&T` and `@T` can only be borrowed if MQ is immutable or const: - MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm - TYPE(LV) = &Ty - MQ == imm | const +```notrust +MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm + TYPE(LV) = &Ty + MQ == imm | const - MUTABILITY(*LV, MQ) // M-Deref-Managed-Imm - TYPE(LV) = @Ty - MQ == imm | const +MUTABILITY(*LV, MQ) // M-Deref-Managed-Imm + TYPE(LV) = @Ty + MQ == imm | const +``` ### Checking mutability of mutable pointer types `&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut: - MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Mut - TYPE(LV) = &mut Ty +```notrust +MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Mut + TYPE(LV) = &mut Ty +``` ## Checking aliasability @@ -328,32 +352,40 @@ Rust code corresponding to this predicate is the function Local variables are never aliasable as they are accessible only within the stack frame. +```notrust ALIASABLE(X, MQ) // M-Var-Mut +``` ### Checking aliasable of owned content Owned content is aliasable if it is found in an aliasable location: - ALIASABLE(LV.f, MQ) // M-Field - ALIASABLE(LV, MQ) +```notrust +ALIASABLE(LV.f, MQ) // M-Field + ALIASABLE(LV, MQ) - ALIASABLE(*LV, MQ) // M-Deref-Unique - ALIASABLE(LV, MQ) +ALIASABLE(*LV, MQ) // M-Deref-Unique + ALIASABLE(LV, MQ) +``` ### Checking mutability of immutable pointer types Immutable pointer types like `&T` are aliasable, and hence can only be borrowed immutably: - ALIASABLE(*LV, imm) // M-Deref-Borrowed-Imm - TYPE(LV) = &Ty +```notrust +ALIASABLE(*LV, imm) // M-Deref-Borrowed-Imm + TYPE(LV) = &Ty +``` ### Checking mutability of mutable pointer types `&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut: - ALIASABLE(*LV, MQ) // M-Deref-Borrowed-Mut - TYPE(LV) = &mut Ty +```notrust +ALIASABLE(*LV, MQ) // M-Deref-Borrowed-Mut + TYPE(LV) = &mut Ty +``` ## Checking lifetime @@ -373,49 +405,63 @@ guaranteed to exist, presuming that no mutations occur. The scope of a local variable is the block where it is declared: - SCOPE(X) = block where X is declared +```notrust + SCOPE(X) = block where X is declared +``` The scope of a field is the scope of the struct: - SCOPE(LV.f) = SCOPE(LV) +```notrust + SCOPE(LV.f) = SCOPE(LV) +``` The scope of a unique referent is the scope of the pointer, since (barring mutation or moves) the pointer will not be freed until the pointer itself `LV` goes out of scope: - SCOPE(*LV) = SCOPE(LV) if LV has type ~T +```notrust + SCOPE(*LV) = SCOPE(LV) if LV has type ~T +``` The scope of a managed referent is also the scope of the pointer. This is a conservative approximation, since there may be other aliases fo that same managed box that would cause it to live longer: - SCOPE(*LV) = SCOPE(LV) if LV has type @T +```notrust + SCOPE(*LV) = SCOPE(LV) if LV has type @T +``` The scope of a borrowed referent is the scope associated with the pointer. This is a conservative approximation, since the data that the pointer points at may actually live longer: - SCOPE(*LV) = LT if LV has type &'LT T or &'LT mut T +```notrust + SCOPE(*LV) = LT if LV has type &'LT T or &'LT mut T +``` ### Checking lifetime of variables The rule for variables states that a variable can only be borrowed a lifetime `LT` that is a subregion of the variable's scope: - LIFETIME(X, LT, MQ) // L-Local - LT <= SCOPE(X) +```notrust +LIFETIME(X, LT, MQ) // L-Local + LT <= SCOPE(X) +``` ### Checking lifetime for owned content The lifetime of a field or owned pointer is the same as the lifetime of its owner: - LIFETIME(LV.f, LT, MQ) // L-Field - LIFETIME(LV, LT, MQ) +```notrust +LIFETIME(LV.f, LT, MQ) // L-Field + LIFETIME(LV, LT, MQ) - LIFETIME(*LV, LT, MQ) // L-Deref-Send - TYPE(LV) = ~Ty - LIFETIME(LV, LT, MQ) +LIFETIME(*LV, LT, MQ) // L-Deref-Send + TYPE(LV) = ~Ty + LIFETIME(LV, LT, MQ) +``` ### Checking lifetime for derefs of references @@ -425,9 +471,11 @@ lifetime. Therefore, the borrow is valid so long as the lifetime `LT` of the borrow is shorter than the lifetime `LT'` of the pointer itself: - LIFETIME(*LV, LT, MQ) // L-Deref-Borrowed - TYPE(LV) = <' Ty OR <' mut Ty - LT <= LT' +```notrust +LIFETIME(*LV, LT, MQ) // L-Deref-Borrowed + TYPE(LV) = <' Ty OR <' mut Ty + LT <= LT' +``` ### Checking lifetime for derefs of managed, immutable pointers @@ -436,11 +484,13 @@ Managed pointers are valid so long as the data within them is when the user guarantees such a root will exist. For this to be true, three conditions must be met: - LIFETIME(*LV, LT, MQ) // L-Deref-Managed-Imm-User-Root - TYPE(LV) = @Ty - LT <= SCOPE(LV) // (1) - LV is immutable // (2) - LV is not moved or not movable // (3) +```notrust +LIFETIME(*LV, LT, MQ) // L-Deref-Managed-Imm-User-Root + TYPE(LV) = @Ty + LT <= SCOPE(LV) // (1) + LV is immutable // (2) + LV is not moved or not movable // (3) +``` Condition (1) guarantees that the managed box will be rooted for at least the lifetime `LT` of the borrow, presuming that no mutation or @@ -468,10 +518,12 @@ borrow without crossing the exit from the scope `LT`. The rule for compiler rooting is as follows: - LIFETIME(*LV, LT, MQ) // L-Deref-Managed-Imm-Compiler-Root - TYPE(LV) = @Ty - LT <= innermost enclosing loop/func - ROOT LV at *LV for LT +```notrust +LIFETIME(*LV, LT, MQ) // L-Deref-Managed-Imm-Compiler-Root + TYPE(LV) = @Ty + LT <= innermost enclosing loop/func + ROOT LV at *LV for LT +``` Here I have written `ROOT LV at *LV FOR LT` to indicate that the code makes a note in a side-table that the box `LV` must be rooted into the @@ -490,9 +542,11 @@ for the lifetime of the loan". Note that there is an initial set of restrictions: these restrictions are computed based on the kind of borrow: - &mut LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM|FREEZE) - &LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM) - &const LV => RESTRICTIONS(LV, LT, []) +```notrust +&mut LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM|FREEZE) +&LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM) +&const LV => RESTRICTIONS(LV, LT, []) +``` The reasoning here is that a mutable borrow must be the only writer, therefore it prevents other writes (`MUTATE`), mutable borrows @@ -505,7 +559,9 @@ moved out from under it, so no actions are forbidden. The simplest case is a borrow of a local variable `X`: - RESTRICTIONS(X, LT, ACTIONS) = (X, ACTIONS) // R-Variable +```notrust +RESTRICTIONS(X, LT, ACTIONS) = (X, ACTIONS) // R-Variable +``` In such cases we just record the actions that are not permitted. @@ -514,8 +570,10 @@ In such cases we just record the actions that are not permitted. Restricting a field is the same as restricting the owner of that field: - RESTRICTIONS(LV.f, LT, ACTIONS) = RS, (LV.f, ACTIONS) // R-Field - RESTRICTIONS(LV, LT, ACTIONS) = RS +```notrust +RESTRICTIONS(LV.f, LT, ACTIONS) = RS, (LV.f, ACTIONS) // R-Field + RESTRICTIONS(LV, LT, ACTIONS) = RS +``` The reasoning here is as follows. If the field must not be mutated, then you must not mutate the owner of the field either, since that @@ -535,9 +593,11 @@ must prevent the owned pointer `LV` from being mutated, which means that we always add `MUTATE` and `CLAIM` to the restriction set imposed on `LV`: - RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Send-Pointer - TYPE(LV) = ~Ty - RESTRICTIONS(LV, LT, ACTIONS|MUTATE|CLAIM) = RS +```notrust +RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Send-Pointer + TYPE(LV) = ~Ty + RESTRICTIONS(LV, LT, ACTIONS|MUTATE|CLAIM) = RS +``` ### Restrictions for loans of immutable managed/borrowed referents @@ -550,14 +610,16 @@ restricting that path. Therefore, the rule for `&Ty` and `@Ty` pointers always returns an empty set of restrictions, and it only permits restricting `MUTATE` and `CLAIM` actions: - RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Managed - TYPE(LV) = @Ty - ACTIONS subset of [MUTATE, CLAIM] +```notrust +RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Managed + TYPE(LV) = @Ty + ACTIONS subset of [MUTATE, CLAIM] - RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed - TYPE(LV) = <' Ty - LT <= LT' // (1) - ACTIONS subset of [MUTATE, CLAIM] +RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed + TYPE(LV) = <' Ty + LT <= LT' // (1) + ACTIONS subset of [MUTATE, CLAIM] +``` The reason that we can restrict `MUTATE` and `CLAIM` actions even without a restrictions list is that it is never legal to mutate nor to @@ -569,17 +631,21 @@ specify that the lifetime of the loan must be less than the lifetime of the `&Ty` pointer. In simple cases, this clause is redundant, since the `LIFETIME()` function will already enforce the required rule: - fn foo(point: &'a Point) -> &'static f32 { - &point.x // Error - } +``` +fn foo(point: &'a Point) -> &'static f32 { + &point.x // Error +} +``` The above example fails to compile both because of clause (1) above but also by the basic `LIFETIME()` check. However, in more advanced examples involving multiple nested pointers, clause (1) is needed: - fn foo(point: &'a &'b mut Point) -> &'b f32 { - &point.x // Error - } +``` +fn foo(point: &'a &'b mut Point) -> &'b f32 { + &point.x // Error +} +``` The `LIFETIME` rule here would accept `'b` because, in fact, the *memory is* guaranteed to remain valid (i.e., not be freed) for the @@ -594,9 +660,11 @@ which is only `'a`, not `'b`. Hence this example yields an error. As a final twist, consider the case of two nested *immutable* pointers, rather than a mutable pointer within an immutable one: - fn foo(point: &'a &'b Point) -> &'b f32 { - &point.x // OK - } +``` +fn foo(point: &'a &'b Point) -> &'b f32 { + &point.x // OK +} +``` This function is legal. The reason for this is that the inner pointer (`*point : &'b Point`) is enough to guarantee the memory is immutable @@ -614,10 +682,12 @@ The rules pertaining to `LIFETIME` exist to ensure that we don't create a borrowed pointer that outlives the memory it points at. So `LIFETIME` prevents a function like this: - fn get_1<'a>() -> &'a int { - let x = 1; - &x - } +``` +fn get_1<'a>() -> &'a int { + let x = 1; + &x +} +``` Here we would be returning a pointer into the stack. Clearly bad. @@ -632,10 +702,12 @@ after we return and hence the remaining code in `'a` cannot possibly mutate it. This distinction is important for type checking functions like this one: - fn inc_and_get<'a>(p: &'a mut Point) -> &'a int { - p.x += 1; - &p.x - } +``` +fn inc_and_get<'a>(p: &'a mut Point) -> &'a int { + p.x += 1; + &p.x +} +``` In this case, we take in a `&mut` and return a frozen borrowed pointer with the same lifetime. So long as the lifetime of the returned value @@ -661,8 +733,10 @@ Because moves from a `&const` or `@const` lvalue are never legal, it is not necessary to add any restrictions at all to the final result. +```notrust RESTRICTIONS(*LV, LT, []) = [] // R-Deref-Freeze-Borrowed TYPE(LV) = &const Ty or @const Ty +``` ### Restrictions for loans of mutable borrowed referents @@ -675,10 +749,12 @@ while the new claimant is live. The rule for mutable borrowed pointers is as follows: - RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Mut-Borrowed - TYPE(LV) = <' mut Ty - LT <= LT' // (1) - RESTRICTIONS(LV, LT, ACTIONS) = RS // (2) +```notrust +RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Mut-Borrowed + TYPE(LV) = <' mut Ty + LT <= LT' // (1) + RESTRICTIONS(LV, LT, ACTIONS) = RS // (2) +``` Let's examine the two numbered clauses: @@ -693,19 +769,21 @@ maximum of `LT'`. Here is a concrete example of a bug this rule prevents: - // Test region-reborrow-from-shorter-mut-ref.rs: - fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { - &mut **p // ERROR due to clause (1) - } - fn main() { - let mut x = 1; - let mut y = &mut x; // <-'b-----------------------------+ - // +-'a--------------------+ | - // v v | - let z = copy_borrowed_ptr(&mut y); // y is lent | - *y += 1; // Here y==z, so both should not be usable... | - *z += 1; // ...and yet they would be, but for clause 1. | - } <---------------------------------------------------------+ +``` +// Test region-reborrow-from-shorter-mut-ref.rs: +fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { + &mut **p // ERROR due to clause (1) +} +fn main() { + let mut x = 1; + let mut y = &mut x; // <-'b-----------------------------+ + // +-'a--------------------+ | + // v v | + let z = copy_borrowed_ptr(&mut y); // y is lent | + *y += 1; // Here y==z, so both should not be usable... | + *z += 1; // ...and yet they would be, but for clause 1. | +} // <------------------------------------------------------+ +``` Clause (2) propagates the restrictions on the referent to the pointer itself. This is the same as with an owned pointer, though the @@ -719,12 +797,14 @@ ways to violate the rules is to move the base pointer to a new name and access it via that new name, thus bypassing the restrictions on the old name. Here is an example: - // src/test/compile-fail/borrowck-move-mut-base-ptr.rs - fn foo(t0: &mut int) { - let p: &int = &*t0; // Freezes `*t0` - let t1 = t0; //~ ERROR cannot move out of `t0` - *t1 = 22; // OK, not a write through `*t0` - } +``` +// src/test/compile-fail/borrowck-move-mut-base-ptr.rs +fn foo(t0: &mut int) { + let p: &int = &*t0; // Freezes `*t0` + let t1 = t0; //~ ERROR cannot move out of `t0` + *t1 = 22; // OK, not a write through `*t0` +} +``` Remember that `&mut` pointers are linear, and hence `let t1 = t0` is a move of `t0` -- or would be, if it were legal. Instead, we get an @@ -737,13 +817,15 @@ danger is to mutably borrow the base path. This can lead to two bad scenarios. The most obvious is that the mutable borrow itself becomes another path to access the same data, as shown here: - // src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs - fn foo<'a>(mut t0: &'a mut int, - mut t1: &'a mut int) { - let p: &int = &*t0; // Freezes `*t0` - let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` - **t2 += 1; // Mutates `*t0` - } +``` +// src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs +fn foo<'a>(mut t0: &'a mut int, + mut t1: &'a mut int) { + let p: &int = &*t0; // Freezes `*t0` + let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` + **t2 += 1; // Mutates `*t0` +} +``` In this example, `**t2` is the same memory as `*t0`. Because `t2` is an `&mut` pointer, `**t2` is a unique path and hence it would be @@ -756,13 +838,15 @@ of `t0`. Hence the claim `&mut t0` is illegal. Another danger with an `&mut` pointer is that we could swap the `t0` value away to create a new path: - // src/test/compile-fail/borrowck-swap-mut-base-ptr.rs - fn foo<'a>(mut t0: &'a mut int, - mut t1: &'a mut int) { - let p: &int = &*t0; // Freezes `*t0` - swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0` - *t1 = 22; - } +``` +// src/test/compile-fail/borrowck-swap-mut-base-ptr.rs +fn foo<'a>(mut t0: &'a mut int, + mut t1: &'a mut int) { + let p: &int = &*t0; // Freezes `*t0` + swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0` + *t1 = 22; +} +``` This is illegal for the same reason as above. Note that if we added back a swap operator -- as we used to have -- we would want to be very @@ -772,14 +856,16 @@ careful to ensure this example is still illegal. referent is claimed, even freezing the base pointer can be dangerous, as shown in the following example: - // src/test/compile-fail/borrowck-borrow-of-mut-base-ptr.rs - fn foo<'a>(mut t0: &'a mut int, - mut t1: &'a mut int) { - let p: &mut int = &mut *t0; // Claims `*t0` - let mut t2 = &t0; //~ ERROR cannot borrow `t0` - let q: &int = &*t2; // Freezes `*t0` but not through `*p` - *p += 1; // violates type of `*q` - } +``` +// src/test/compile-fail/borrowck-borrow-of-mut-base-ptr.rs +fn foo<'a>(mut t0: &'a mut int, + mut t1: &'a mut int) { + let p: &mut int = &mut *t0; // Claims `*t0` + let mut t2 = &t0; //~ ERROR cannot borrow `t0` + let q: &int = &*t2; // Freezes `*t0` but not through `*p` + *p += 1; // violates type of `*q` +} +``` Here the problem is that `*t0` is claimed by `p`, and hence `p` wants to be the controlling pointer through which mutation or freezes occur. @@ -793,26 +879,30 @@ which is clearly unsound. However, it is not always unsafe to freeze the base pointer. In particular, if the referent is frozen, there is no harm in it: - // src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs - fn foo<'a>(mut t0: &'a mut int, - mut t1: &'a mut int) { - let p: &int = &*t0; // Freezes `*t0` - let mut t2 = &t0; - let q: &int = &*t2; // Freezes `*t0`, but that's ok... - let r: &int = &*t0; // ...after all, could do same thing directly. - } +``` +// src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs +fn foo<'a>(mut t0: &'a mut int, + mut t1: &'a mut int) { + let p: &int = &*t0; // Freezes `*t0` + let mut t2 = &t0; + let q: &int = &*t2; // Freezes `*t0`, but that's ok... + let r: &int = &*t0; // ...after all, could do same thing directly. +} +``` In this case, creating the alias `t2` of `t0` is safe because the only thing `t2` can be used for is to further freeze `*t0`, which is already frozen. In particular, we cannot assign to `*t0` through the new alias `t2`, as demonstrated in this test case: - // src/test/run-pass/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs - fn foo(t0: & &mut int) { - let t1 = t0; - let p: &int = &**t0; - **t1 = 22; //~ ERROR cannot assign - } +``` +// src/test/run-pass/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs +fn foo(t0: & &mut int) { + let t1 = t0; + let p: &int = &**t0; + **t1 = 22; //~ ERROR cannot assign +} +``` This distinction is reflected in the rules. When doing an `&mut` borrow -- as in the first example -- the set `ACTIONS` will be @@ -876,22 +966,24 @@ moves/uninitializations of the variable that is being used. Let's look at a simple example: - fn foo(a: ~int) { - let b: ~int; // Gen bit 0. +``` +fn foo(a: ~int) { + let b: ~int; // Gen bit 0. - if cond { // Bits: 0 - use(&*a); - b = a; // Gen bit 1, kill bit 0. - use(&*b); - } else { - // Bits: 0 - } - // Bits: 0,1 - use(&*a); // Error. - use(&*b); // Error. + if cond { // Bits: 0 + use(&*a); + b = a; // Gen bit 1, kill bit 0. + use(&*b); + } else { + // Bits: 0 } + // Bits: 0,1 + use(&*a); // Error. + use(&*b); // Error. +} - fn use(a: &int) { } +fn use(a: &int) { } +``` In this example, the variable `b` is created uninitialized. In one branch of an `if`, we then move the variable `a` into `b`. Once we diff --git a/src/librustc/middle/typeck/infer/doc.rs b/src/librustc/middle/typeck/infer/doc.rs index 539418dbcb2..5fa611a1fe2 100644 --- a/src/librustc/middle/typeck/infer/doc.rs +++ b/src/librustc/middle/typeck/infer/doc.rs @@ -45,11 +45,13 @@ There are several critical invariants which we maintain: > types lie in between. The bottom type is then the Null type. > So the tree looks like: > -> Object -> / \ -> String Other -> \ / -> (null) +> ```notrust +> Object +> / \ +> String Other +> \ / +> (null) +> ``` > > So the upper bound type is the "supertype" and the lower bound is the > "subtype" (also, super and sub mean upper and lower in Latin, or something @@ -104,18 +106,20 @@ Pictorally, what this does is to take two distinct variables with (hopefully not completely) distinct type ranges and produce one with the intersection. - B.ub B.ub - /\ / - A.ub / \ A.ub / - / \ / \ \ / - / X \ UB - / / \ \ / \ - / / / \ / / - \ \ / / \ / - \ X / LB - \ / \ / / \ - \ / \ / / \ - A.lb B.lb A.lb B.lb +```notrust + B.ub B.ub + /\ / + A.ub / \ A.ub / + / \ / \ \ / + / X \ UB + / / \ \ / \ + / / / \ / / + \ \ / / \ / + \ X / LB + \ / \ / / \ + \ / \ / / \ + A.lb B.lb A.lb B.lb +``` ### Option 2: Relate UB/LB @@ -125,20 +129,22 @@ bounds in such a way that, whatever happens, we know that A <: B will hold. This can be achieved by ensuring that A.ub <: B.lb. In practice there are two ways to do that, depicted pictorally here: - Before Option #1 Option #2 +```notrust + Before Option #1 Option #2 - B.ub B.ub B.ub - /\ / \ / \ - A.ub / \ A.ub /(B')\ A.ub /(B')\ - / \ / \ \ / / \ / / - / X \ __UB____/ UB / - / / \ \ / | | / - / / / \ / | | / - \ \ / / /(A')| | / - \ X / / LB ______LB/ - \ / \ / / / \ / (A')/ \ - \ / \ / \ / \ \ / \ - A.lb B.lb A.lb B.lb A.lb B.lb + B.ub B.ub B.ub + /\ / \ / \ + A.ub / \ A.ub /(B')\ A.ub /(B')\ + / \ / \ \ / / \ / / + / X \ __UB____/ UB / + / / \ \ / | | / + / / / \ / | | / + \ \ / / /(A')| | / + \ X / / LB ______LB/ + \ / \ / / / \ / (A')/ \ + \ / \ / \ / \ \ / \ + A.lb B.lb A.lb B.lb A.lb B.lb +``` In these diagrams, UB and LB are defined as before. As you can see, the new ranges `A'` and `B'` are quite different from the range that @@ -158,13 +164,15 @@ course, it depends on the program. The main case which fails today that I would like to support is: - fn foo(x: T, y: T) { ... } +```notrust +fn foo(x: T, y: T) { ... } - fn bar() { - let x: @mut int = @mut 3; - let y: @int = @3; - foo(x, y); - } +fn bar() { + let x: @mut int = @mut 3; + let y: @int = @3; + foo(x, y); +} +``` In principle, the inferencer ought to find that the parameter `T` to `foo(x, y)` is `@const int`. Today, however, it does not; this is diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 99ac07ba4d7..ded80295320 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -59,7 +59,7 @@ associated with. It is only not `None` when the associated field has an identifier in the source code. For example, the `x`s in the following snippet -~~~ignore +~~~notrust struct A { x : int } struct B(int); @@ -83,7 +83,7 @@ variants, it is represented as a count of 0. The following simplified `Eq` is used for in-code examples: -~~~ignore +~~~notrust trait Eq { fn eq(&self, other: &Self); } @@ -101,7 +101,7 @@ above `Eq`, `A`, `B` and `C`. When generating the `expr` for the `A` impl, the `SubstructureFields` is -~~~ignore +~~~notrust Struct(~[FieldInfo { span: name: Some(), @@ -112,7 +112,7 @@ Struct(~[FieldInfo { For the `B` impl, called with `B(a)` and `B(b)`, -~~~ignore +~~~notrust Struct(~[FieldInfo { span: , name: None, @@ -126,7 +126,7 @@ Struct(~[FieldInfo { When generating the `expr` for a call with `self == C0(a)` and `other == C0(b)`, the SubstructureFields is -~~~ignore +~~~notrust EnumMatching(0, , ~[FieldInfo { span: @@ -138,7 +138,7 @@ EnumMatching(0, , For `C1 {x}` and `C1 {x}`, -~~~ignore +~~~notrust EnumMatching(1, , ~[FieldInfo { span: @@ -150,7 +150,7 @@ EnumMatching(1, , For `C0(a)` and `C1 {x}` , -~~~ignore +~~~notrust EnumNonMatching(~[(0, , ~[(, None, )]), (1, , @@ -164,7 +164,7 @@ EnumNonMatching(~[(0, , A static method on the above would result in, -~~~~ignore +~~~~notrust StaticStruct(, Named(~[(, )])) StaticStruct(, Unnamed(~[])) @@ -625,7 +625,7 @@ impl<'a> MethodDef<'a> { } /** - ~~~ignore + ~~~ #[deriving(Eq)] struct A { x: int, y: int } @@ -725,7 +725,7 @@ impl<'a> MethodDef<'a> { } /** - ~~~ignore + ~~~ #[deriving(Eq)] enum A { A1 @@ -768,7 +768,7 @@ impl<'a> MethodDef<'a> { /** Creates the nested matches for an enum definition recursively, i.e. - ~~~ignore + ~~~notrust match self { Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... }, Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... }, @@ -1172,7 +1172,7 @@ pub fn cs_fold(use_foldl: bool, Call the method that is being derived on all the fields, and then process the collected results. i.e. -~~~ignore +~~~ f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1), self_2.method(__arg_1_2, __arg_2_2)]) ~~~