Skip to content

Commit 9339585

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

File tree

1 file changed

+21
-16
lines changed

1 file changed

+21
-16
lines changed

src/types/closure.md

+21-16
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,14 @@ let c = || match x {
106106

107107
### Capturing references in move contexts
108108

109-
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.
109+
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.
110110

111111
```rust
112112
struct T(String, String);
113113

114114
let mut t = T(String::from("foo"), String::from("bar"));
115115
let t = &mut t;
116-
let c = move || t.0.truncate(0); // closure captures (&mut t.0)
116+
let c = move || t.0.truncate(0); // closure captures `t`
117117
```
118118

119119
### Raw pointer dereference
@@ -325,10 +325,11 @@ If a closure captures a field of a composite types such as structs, tuples, and
325325
* Cleanup and truncation
326326
* Generate C' by mapping each (Mode, Place) in C:
327327
* `(Place1, Mode1) = ref_opt(unsafe_check(Place, Mode))`
328-
* if this is a ref closure:
329-
* Add `ref_xform(Place1, Mode1)` to C'
328+
* `(Place2, Mode2)` = if this is a ref closure:
329+
* `ref_xform(Place1, Mode1)`
330330
* else:
331-
* Add `move_xform(Place1, Mode1)` to C'
331+
* `move_xform(Place1, Mode1)`
332+
* Add `(Place3, Mode3) = truncate_move_through_drop(Place2, Mode2)` to C'.
332333
* Minimization
333334
* Until no rules apply:
334335
* For each two places (P1, M1), (P2, M2) where P1 is a prefix of P2:
@@ -346,18 +347,12 @@ If a closure captures a field of a composite types such as structs, tuples, and
346347
* Else
347348
* Return (Place, Mode)
348349
* `move_xform(Place, Mode) -> (Place, Mode)` (For move closures)
349-
* "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)."
350-
* "When taking ownership, only capture data found on the stack."
351-
* "Otherwise, reborrow the reference."
352-
* If Mode is `ref mut` and the place contains a deref of an `&mut`:
353-
* Return (Place, Mode)
354-
* Else if Mode is `ref *` and the place contains a deref of an `&`:
355-
* Return (Place, Mode)
356-
* Else if place contains a deref at index `i`:
350+
* If place contains a deref at index `i`:
357351
* Let `(Place1, _) = truncate_place(Place, Mode, i)`
358352
* Return (Place1, ByValue)
359353
* Else:
360354
* Return (Place, ByValue)
355+
* 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).
361356
* `ref_xform(Place, Mode) -> (Place, Mode)` (for ref closures)
362357
* "If taking ownership of data, only move data from enclosing stack frame."
363358
* Generate C' by mapping each (Mode, Place) in C
@@ -378,6 +373,16 @@ If a closure captures a field of a composite types such as structs, tuples, and
378373
and `Place.type_before_projection(l) = ty::Ref(.., Mutability::Not)`
379374
* Let Place1 = (Base, Projections[0..=l])
380375
* Return (Place1, Ref)
376+
* `truncate_move_through_drop(Place1, Mode1) -> (Place, Mode)`
377+
* Rust doesn't permit moving out of a type that implements drop
378+
* In the case where we do a disjoint capture in a move closure, we might end up trying to move out of drop type
379+
* We truncate move of not-Copy types
380+
* If Mode1 != ByBalue
381+
* return (Place1, Mode1)
382+
* If there exists `i` such that `Place1.before_projection(i): Drop` and `Place1.ty()` doesn't impl `Copy`
383+
* then return `truncate_place(Place1, Mode1, i)`
384+
* Else return (Place1, Mode1)
385+
* Check [rust-lang/rust#88476](https://github.com/rust-lang/rust/issues/88476) for examples.
381386
* `truncate_place(Place, Mode, len) -> (Place, Mode)`
382387
* "Truncate the place to length `len`, i.e. upto but not including index `len`"
383388
* "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"
@@ -397,11 +402,11 @@ struct Foo { x: i32 }
397402

398403
fn box_mut() {
399404
let mut s = Foo { x: 0 } ;
400-
405+
401406
let px = &mut s;
402407
let bx = Box::new(px);
403-
404-
408+
409+
405410
let c = move || bx.x += 10;
406411
// Mutable reference to this place:
407412
// (*(*bx)).x

0 commit comments

Comments
 (0)