Skip to content

Commit bf995cc

Browse files
arora-amanehuss
authored andcommitted
Update closure algorithm per #88467 #88477
1 parent 3679997 commit bf995cc

File tree

1 file changed

+21
-16
lines changed

1 file changed

+21
-16
lines changed

src/types/closure.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,14 @@ let c = || match x {
111111

112112
### Capturing references in move contexts
113113

114-
Moving fields out of references is not allowed. As a result, in the case of move closures, when values accessed through a shared references are moved into the closure body, the compiler, instead of moving the values out of the reference, would reborrow the data.
114+
Moving fields out of references is not allowed. As a result, in the case of move closures, when values accessed through a shared references are moved into the closure body, the compiler will truncate right before a dereference.
115115

116116
```rust
117117
struct T(String, String);
118118

119119
let mut t = T(String::from("foo"), String::from("bar"));
120120
let t = &mut t;
121-
let c = move || t.0.truncate(0); // closure captures (&mut t.0)
121+
let c = move || t.0.truncate(0); // closure captures `t`
122122
```
123123

124124
### Raw pointer dereference
@@ -339,10 +339,11 @@ If a closure captures a field of a composite types such as structs, tuples, and
339339
* Cleanup and truncation
340340
* Generate C' by mapping each (Mode, Place) in C:
341341
* `(Place1, Mode1) = ref_opt(unsafe_check(Place, Mode))`
342-
* if this is a ref closure:
343-
* Add `ref_xform(Place1, Mode1)` to C'
342+
* `(Place2, Mode2)` = if this is a ref closure:
343+
* `ref_xform(Place1, Mode1)`
344344
* else:
345-
* Add `move_xform(Place1, Mode1)` to C'
345+
* `move_xform(Place1, Mode1)`
346+
* Add `(Place3, Mode3) = truncate_move_through_drop(Place2, Mode2)` to C'.
346347
* Minimization
347348
* Until no rules apply:
348349
* For each two places (P1, M1), (P2, M2) where P1 is a prefix of P2:
@@ -360,18 +361,12 @@ If a closure captures a field of a composite types such as structs, tuples, and
360361
* Else
361362
* Return (Place, Mode)
362363
* `move_xform(Place, Mode) -> (Place, Mode)` (For move closures)
363-
* "Take ownership if data being accessed is owned by the variable used to access it (or if closure attempts to move data that it doesn't own)."
364-
* "When taking ownership, only capture data found on the stack."
365-
* "Otherwise, reborrow the reference."
366-
* If Mode is `ref mut` and the place contains a deref of an `&mut`:
367-
* Return (Place, Mode)
368-
* Else if Mode is `ref *` and the place contains a deref of an `&`:
369-
* Return (Place, Mode)
370-
* Else if place contains a deref at index `i`:
364+
* If place contains a deref at index `i`:
371365
* Let `(Place1, _) = truncate_place(Place, Mode, i)`
372366
* Return (Place1, ByValue)
373367
* Else:
374368
* Return (Place, ByValue)
369+
* Note that initially we had considered an approach where "Take ownership if data being accessed is owned by the variable used to access it (or if closure attempts to move data that it doesn't own). That is when taking ownership only capture data that is found on the stack otherwise reborrow the reference.". This cause a bug around lifetimes, check [rust-lang/rust#88431](https://github.com/rust-lang/rust/issues/88431).
375370
* `ref_xform(Place, Mode) -> (Place, Mode)` (for ref closures)
376371
* "If taking ownership of data, only move data from enclosing stack frame."
377372
* Generate C' by mapping each (Mode, Place) in C
@@ -392,6 +387,16 @@ If a closure captures a field of a composite types such as structs, tuples, and
392387
and `Place.type_before_projection(l) = ty::Ref(.., Mutability::Not)`
393388
* Let Place1 = (Base, Projections[0..=l])
394389
* Return (Place1, Ref)
390+
* `truncate_move_through_drop(Place1, Mode1) -> (Place, Mode)`
391+
* Rust doesn't permit moving out of a type that implements drop
392+
* In the case where we do a disjoint capture in a move closure, we might end up trying to move out of drop type
393+
* We truncate move of not-Copy types
394+
* If Mode1 != ByBalue
395+
* return (Place1, Mode1)
396+
* If there exists `i` such that `Place1.before_projection(i): Drop` and `Place1.ty()` doesn't impl `Copy`
397+
* then return `truncate_place(Place1, Mode1, i)`
398+
* Else return (Place1, Mode1)
399+
* Check [rust-lang/rust#88476](https://github.com/rust-lang/rust/issues/88476) for examples.
395400
* `truncate_place(Place, Mode, len) -> (Place, Mode)`
396401
* "Truncate the place to length `len`, i.e. upto but not including index `len`"
397402
* "If during truncation we drop Deref of a `&mut` and the place was being used by `ref mut`, the access to the truncated place must be unique"
@@ -411,11 +416,11 @@ struct Foo { x: i32 }
411416

412417
fn box_mut() {
413418
let mut s = Foo { x: 0 } ;
414-
419+
415420
let px = &mut s;
416421
let bx = Box::new(px);
417-
418-
422+
423+
419424
let c = move || bx.x += 10;
420425
// Mutable reference to this place:
421426
// (*(*bx)).x

0 commit comments

Comments
 (0)