@@ -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,19 +1626,16 @@ 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
) ;
1633
1637
1634
- let place = restrict_preicision_for_box ( & place, self . capture_clause ) ;
1635
-
1636
1638
let place_with_id = PlaceWithHirId { place, ..* place_with_id } ;
1637
- debug ! (
1638
- "borrow after restrictions:(place_with_id={:?}, diag_expr_id={:?}, bk={:?})" ,
1639
- place_with_id, diag_expr_id, bk
1640
- ) ;
1641
1639
1642
1640
if !self . capture_information . contains_key ( & place_with_id. place ) {
1643
1641
self . init_capture_info_for_place ( & place_with_id, diag_expr_id) ;
@@ -1661,39 +1659,46 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1661
1659
}
1662
1660
}
1663
1661
1664
- // In case of move closures we don't want to capture derefs on a box.
1665
- // This is motivated by:
1666
- // 1. We only want to capture data that is on the stack
1667
- // 2. One motivatiton for the user to use a box might be to reduce the amount of data that gets
1668
- // moved (if size of pointer < size of data). We want to make sure that this optimization that
1669
- // the user made is respected.
1670
- fn restrict_preicision_for_box ( place : & Place < ' tcx > , capture_by : hir:: CaptureBy ) -> Place < ' tcx > {
1671
- let mut rv = place. clone ( ) ;
1672
- match capture_by {
1673
- hir:: CaptureBy :: Ref => rv,
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 => { }
1674
1673
hir:: CaptureBy :: Value => {
1675
1674
if ty:: TyS :: is_box ( place. base_ty ) {
1676
- Place { projections : Vec :: new ( ) , ..rv }
1675
+ place . projections . truncate ( 0 ) ;
1677
1676
} else {
1678
1677
// Either the box is the last access or there is a deref applied on the box
1679
1678
// In either case we want to stop at the box.
1680
1679
let pos = place. projections . iter ( ) . position ( |proj| ty:: TyS :: is_box ( proj. ty ) ) ;
1681
1680
match pos {
1682
- None => rv ,
1681
+ None => { }
1683
1682
Some ( idx) => {
1684
- Place { projections : rv . projections . drain ( 0 ..= idx) . collect ( ) , ..rv }
1683
+ place . projections . truncate ( idx + 1 ) ;
1685
1684
}
1686
1685
}
1687
1686
}
1688
1687
}
1689
1688
}
1689
+
1690
+ place
1690
1691
}
1691
1692
1692
1693
/// Truncate projections so that following rules are obeyed by the captured `place`:
1693
1694
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
1694
1695
/// them completely.
1695
1696
/// - No Index projections are captured, since arrays are captured completely.
1696
- 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 > {
1697
1702
if place. projections . is_empty ( ) {
1698
1703
// Nothing to do here
1699
1704
return place;
@@ -1728,7 +1733,8 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
1728
1733
1729
1734
place. projections . truncate ( length) ;
1730
1735
1731
- place
1736
+ // Dont't capture projections on top of a box in move closures.
1737
+ restrict_precision_for_box ( capture_clause, place)
1732
1738
}
1733
1739
1734
1740
/// Truncates a place so that the resultant capture doesn't move data out of a reference
0 commit comments