@@ -167,7 +167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
167167 ) ;
168168 self . log_capture_analysis_first_pass ( closure_def_id, & delegate. capture_information , span) ;
169169
170- self . compute_min_captures ( closure_def_id, delegate. capture_information ) ;
170+ self . compute_min_captures ( closure_def_id, capture_clause , delegate. capture_information ) ;
171171
172172 let closure_hir_id = self . tcx . hir ( ) . local_def_id_to_hir_id ( local_def_id) ;
173173
@@ -200,7 +200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
200200 }
201201
202202 // 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) ;
204204 }
205205
206206 if let Some ( closure_substs) = infer_kind {
@@ -213,7 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
213213 // If we have an origin, store it.
214214 if let Some ( origin) = delegate. current_origin . clone ( ) {
215215 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 ) )
217217 } else {
218218 ( origin. 0 , Place { projections : vec ! [ ] , ..origin. 1 } )
219219 } ;
@@ -368,6 +368,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368368 fn compute_min_captures (
369369 & self ,
370370 closure_def_id : DefId ,
371+ capture_clause : hir:: CaptureBy ,
371372 capture_information : InferredCaptureInformation < ' tcx > ,
372373 ) {
373374 if capture_information. is_empty ( ) {
@@ -385,7 +386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
385386 base => bug ! ( "Expected upvar, found={:?}" , base) ,
386387 } ;
387388
388- let place = restrict_capture_precision ( place) ;
389+ let place = restrict_capture_precision ( capture_clause , place) ;
389390
390391 let min_cap_list = match root_var_min_capture_list. get_mut ( & var_hir_id) {
391392 None => {
@@ -1590,7 +1591,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
15901591 if let PlaceBase :: Upvar ( _) = place. base {
15911592 // We need to restrict Fake Read precision to avoid fake reading unsafe code,
15921593 // such as deref of a raw pointer.
1593- let place = restrict_capture_precision ( place) ;
1594+ let place = restrict_capture_precision ( self . capture_clause , place) ;
15941595 let place =
15951596 restrict_repr_packed_field_ref_capture ( self . fcx . tcx , self . fcx . param_env , & place) ;
15961597 self . fake_reads . push ( ( place, cause, diag_expr_id) ) ;
@@ -1625,11 +1626,15 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
16251626 place_with_id, diag_expr_id, bk
16261627 ) ;
16271628
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`.
16281632 let place = restrict_repr_packed_field_ref_capture (
16291633 self . fcx . tcx ,
16301634 self . fcx . param_env ,
16311635 & place_with_id. place ,
16321636 ) ;
1637+
16331638 let place_with_id = PlaceWithHirId { place, ..* place_with_id } ;
16341639
16351640 if !self . capture_information . contains_key ( & place_with_id. place ) {
@@ -1654,11 +1659,46 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
16541659 }
16551660}
16561661
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+
16571693/// Truncate projections so that following rules are obeyed by the captured `place`:
16581694/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
16591695/// them completely.
16601696/// - 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 > {
16621702 if place. projections . is_empty ( ) {
16631703 // Nothing to do here
16641704 return place;
@@ -1693,7 +1733,8 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
16931733
16941734 place. projections . truncate ( length) ;
16951735
1696- place
1736+ // Dont't capture projections on top of a box in move closures.
1737+ restrict_precision_for_box ( capture_clause, place)
16971738}
16981739
16991740/// Truncates a place so that the resultant capture doesn't move data out of a reference
0 commit comments