@@ -167,7 +167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
167
167
) ;
168
168
self . log_capture_analysis_first_pass ( closure_def_id, & delegate. capture_information , span) ;
169
169
170
- self . compute_min_captures ( closure_def_id, delegate. capture_information ) ;
170
+ self . compute_min_captures ( closure_def_id, capture_clause , delegate. capture_information ) ;
171
171
172
172
let closure_hir_id = self . tcx . hir ( ) . local_def_id_to_hir_id ( local_def_id) ;
173
173
@@ -200,7 +200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
200
200
}
201
201
202
202
// This will update the min captures based on this new fake information.
203
- self . compute_min_captures ( closure_def_id, capture_information) ;
203
+ self . compute_min_captures ( closure_def_id, capture_clause , capture_information) ;
204
204
}
205
205
206
206
if let Some ( closure_substs) = infer_kind {
@@ -213,7 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
213
213
// If we have an origin, store it.
214
214
if let Some ( origin) = delegate. current_origin . clone ( ) {
215
215
let origin = if enable_precise_capture ( self . tcx , span) {
216
- ( origin. 0 , restrict_capture_precision ( origin. 1 ) )
216
+ ( origin. 0 , restrict_capture_precision ( capture_clause , origin. 1 ) )
217
217
} else {
218
218
( origin. 0 , Place { projections : vec ! [ ] , ..origin. 1 } )
219
219
} ;
@@ -368,6 +368,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368
368
fn compute_min_captures (
369
369
& self ,
370
370
closure_def_id : DefId ,
371
+ capture_clause : hir:: CaptureBy ,
371
372
capture_information : InferredCaptureInformation < ' tcx > ,
372
373
) {
373
374
if capture_information. is_empty ( ) {
@@ -385,7 +386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
385
386
base => bug ! ( "Expected upvar, found={:?}" , base) ,
386
387
} ;
387
388
388
- let place = restrict_capture_precision ( place) ;
389
+ let place = restrict_capture_precision ( capture_clause , place) ;
389
390
390
391
let min_cap_list = match root_var_min_capture_list. get_mut ( & var_hir_id) {
391
392
None => {
@@ -1590,7 +1591,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1590
1591
if let PlaceBase :: Upvar ( _) = place. base {
1591
1592
// We need to restrict Fake Read precision to avoid fake reading unsafe code,
1592
1593
// such as deref of a raw pointer.
1593
- let place = restrict_capture_precision ( place) ;
1594
+ let place = restrict_capture_precision ( self . capture_clause , place) ;
1594
1595
let place =
1595
1596
restrict_repr_packed_field_ref_capture ( self . fcx . tcx , self . fcx . param_env , & place) ;
1596
1597
self . fake_reads . push ( ( place, cause, diag_expr_id) ) ;
@@ -1625,11 +1626,15 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1625
1626
place_with_id, diag_expr_id, bk
1626
1627
) ;
1627
1628
1629
+ // We only want repr packed restriction to be applied to reading references into a packed
1630
+ // struct, and not when the data is being moved. There for we call this method here instead
1631
+ // of in `restrict_capture_precision`.
1628
1632
let place = restrict_repr_packed_field_ref_capture (
1629
1633
self . fcx . tcx ,
1630
1634
self . fcx . param_env ,
1631
1635
& place_with_id. place ,
1632
1636
) ;
1637
+
1633
1638
let place_with_id = PlaceWithHirId { place, ..* place_with_id } ;
1634
1639
1635
1640
if !self . capture_information . contains_key ( & place_with_id. place ) {
@@ -1654,11 +1659,46 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1654
1659
}
1655
1660
}
1656
1661
1662
+ /// Deref of a box isn't captured in move clousres. This is motivated by:
1663
+ /// 1. We only want to capture data that is on the stack
1664
+ /// 2. One motivation for the user to use a box might be to reduce the amount of data that gets
1665
+ /// moved (if size of pointer < size of data). We want to make sure that this optimization that
1666
+ /// the user made is respected.
1667
+ fn restrict_precision_for_box < ' tcx > (
1668
+ capture_clause : hir:: CaptureBy ,
1669
+ mut place : Place < ' tcx > ,
1670
+ ) -> Place < ' tcx > {
1671
+ match capture_clause {
1672
+ hir:: CaptureBy :: Ref => { }
1673
+ hir:: CaptureBy :: Value => {
1674
+ if ty:: TyS :: is_box ( place. base_ty ) {
1675
+ place. projections . truncate ( 0 ) ;
1676
+ } else {
1677
+ // Either the box is the last access or there is a deref applied on the box
1678
+ // In either case we want to stop at the box.
1679
+ let pos = place. projections . iter ( ) . position ( |proj| ty:: TyS :: is_box ( proj. ty ) ) ;
1680
+ match pos {
1681
+ None => { }
1682
+ Some ( idx) => {
1683
+ place. projections . truncate ( idx + 1 ) ;
1684
+ }
1685
+ }
1686
+ }
1687
+ }
1688
+ }
1689
+
1690
+ place
1691
+ }
1692
+
1657
1693
/// Truncate projections so that following rules are obeyed by the captured `place`:
1658
1694
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
1659
1695
/// them completely.
1660
1696
/// - No Index projections are captured, since arrays are captured completely.
1661
- fn restrict_capture_precision < ' tcx > ( mut place : Place < ' tcx > ) -> Place < ' tcx > {
1697
+ /// - Deref of a box isn't captured in move clousres.
1698
+ fn restrict_capture_precision < ' tcx > (
1699
+ capture_clause : hir:: CaptureBy ,
1700
+ mut place : Place < ' tcx > ,
1701
+ ) -> Place < ' tcx > {
1662
1702
if place. projections . is_empty ( ) {
1663
1703
// Nothing to do here
1664
1704
return place;
@@ -1693,7 +1733,8 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
1693
1733
1694
1734
place. projections . truncate ( length) ;
1695
1735
1696
- place
1736
+ // Dont't capture projections on top of a box in move closures.
1737
+ restrict_precision_for_box ( capture_clause, place)
1697
1738
}
1698
1739
1699
1740
/// Truncates a place so that the resultant capture doesn't move data out of a reference
0 commit comments