@@ -148,9 +148,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
148148 fcx : self ,
149149 closure_def_id,
150150 closure_span : span,
151- capture_clause,
152- _current_closure_kind : ty:: ClosureKind :: LATTICE_BOTTOM ,
153- _current_origin : None ,
154151 capture_information : Default :: default ( ) ,
155152 fake_reads : Default :: default ( ) ,
156153 } ;
@@ -309,6 +306,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
309306 . collect ( )
310307 }
311308
309+ /// Adjusts the closure capture information to ensure that the operations aren't unasfe,
310+ /// and that the path can be captured with required capture kind (depending on use in closure,
311+ /// move closure etc.)
312+ ///
313+ /// Returns the set of of adjusted information along with the inferred closure kind and span
314+ /// associated with the closure kind inference.
315+ ///
316+ /// Note that we *always* infer a minimal kind, even if
317+ /// we don't always *use* that in the final result (i.e., sometimes
318+ /// we've taken the closure kind from the expectations instead, and
319+ /// for generators we don't even implement the closure traits
320+ /// really).
321+ ///
322+ /// If we inferred that the closure needs to be FnMut/FnOnce, last element of the returned tuplle
323+ /// contains a `Some()` with the `Place` that caused us to do so.
312324 fn process_collected_capture_information (
313325 & self ,
314326 capture_clause : hir:: CaptureBy ,
@@ -320,7 +332,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
320332 let mut origin: Option < ( Span , Place < ' tcx > ) > = None ;
321333
322334 for ( place, mut capture_info) in capture_information. into_iter ( ) {
323- let place = restrict_capture_precision ( capture_clause, place) ;
335+ // Apply rules for safety before inferring closure kind
336+ let place = restrict_capture_precision ( place) ;
337+
324338 let usage_span = if let Some ( usage_expr) = capture_info. path_expr_id {
325339 self . tcx . hir ( ) . span ( usage_expr)
326340 } else {
@@ -356,8 +370,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
356370 origin = updated. 1 ;
357371
358372 let ( place, capture_kind) = match capture_clause {
359- hir:: CaptureBy :: Value => process_for_move ( place, capture_info. capture_kind ) ,
360- hir:: CaptureBy :: Ref => process_for_ref ( place, capture_info. capture_kind ) ,
373+ hir:: CaptureBy :: Value => adjust_for_move_closure ( place, capture_info. capture_kind ) ,
374+ hir:: CaptureBy :: Ref => {
375+ adjust_for_non_move_closure ( place, capture_info. capture_kind )
376+ }
361377 } ;
362378
363379 capture_info. capture_kind = capture_kind;
@@ -1386,20 +1402,6 @@ struct InferBorrowKind<'a, 'tcx> {
13861402
13871403 closure_span : Span ,
13881404
1389- capture_clause : hir:: CaptureBy ,
1390-
1391- // The kind that we have inferred that the current closure
1392- // requires. Note that we *always* infer a minimal kind, even if
1393- // we don't always *use* that in the final result (i.e., sometimes
1394- // we've taken the closure kind from the expectations instead, and
1395- // for generators we don't even implement the closure traits
1396- // really).
1397- _current_closure_kind : ty:: ClosureKind ,
1398-
1399- // If we modified `current_closure_kind`, this field contains a `Some()` with the
1400- // variable access that caused us to do so.
1401- _current_origin : Option < ( Span , Place < ' tcx > ) > ,
1402-
14031405 /// For each Place that is captured by the closure, we track the minimal kind of
14041406 /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
14051407 ///
@@ -1442,7 +1444,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
14421444 place_with_id, diag_expr_id, mode
14431445 ) ;
14441446
1445- // AMAN: Don't upgrade copy types to ByValue
1447+ // Copy type being used as ByValue are equivalent to ImmBorrow and don't require any
1448+ // escalation.
14461449 match mode {
14471450 euv:: ConsumeMode :: Copy => return ,
14481451 euv:: ConsumeMode :: Move => { }
@@ -1589,8 +1592,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
15891592 if let PlaceBase :: Upvar ( upvar_id) = place_with_id. place . base {
15901593 assert_eq ! ( self . closure_def_id. expect_local( ) , upvar_id. closure_expr_id) ;
15911594
1592- // AMAN: Always initialize to ImmBorrow
1593- // We will increase the CaptureKind in process_collected_capture_information.
1595+ // Initialize to ImmBorrow
1596+ // We will escalate the CaptureKind based on any uses we see or in ` process_collected_capture_information` .
15941597 let origin = UpvarRegion ( upvar_id, self . closure_span ) ;
15951598 let upvar_region = self . fcx . next_region_var ( origin) ;
15961599 let upvar_borrow = ty:: UpvarBorrow { kind : ty:: ImmBorrow , region : upvar_region } ;
@@ -1617,7 +1620,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
16171620 if let PlaceBase :: Upvar ( _) = place. base {
16181621 // We need to restrict Fake Read precision to avoid fake reading unsafe code,
16191622 // such as deref of a raw pointer.
1620- let place = restrict_capture_precision ( self . capture_clause , place) ;
1623+ let place = restrict_capture_precision ( place) ;
16211624 let place =
16221625 restrict_repr_packed_field_ref_capture ( self . fcx . tcx , self . fcx . param_env , & place) ;
16231626 self . fake_reads . push ( ( place, cause, diag_expr_id) ) ;
@@ -1659,7 +1662,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
16591662 ) ;
16601663
16611664 // We only want repr packed restriction to be applied to reading references into a packed
1662- // struct, and not when the data is being moved. There for we call this method here instead
1665+ // struct, and not when the data is being moved. Therefore we call this method here instead
16631666 // of in `restrict_capture_precision`.
16641667 let place = restrict_repr_packed_field_ref_capture (
16651668 self . fcx . tcx ,
@@ -1697,10 +1700,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
16971700/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
16981701/// them completely.
16991702/// - No Index projections are captured, since arrays are captured completely.
1700- fn restrict_capture_precision < ' tcx > (
1701- _capture_clause : hir:: CaptureBy ,
1702- mut place : Place < ' tcx > ,
1703- ) -> Place < ' tcx > {
1703+ fn restrict_capture_precision < ' tcx > ( mut place : Place < ' tcx > ) -> Place < ' tcx > {
17041704 if place. projections . is_empty ( ) {
17051705 // Nothing to do here
17061706 return place;
@@ -1738,19 +1738,22 @@ fn restrict_capture_precision<'tcx>(
17381738 place
17391739}
17401740
1741- fn process_for_move < ' tcx > (
1741+ /// Take ownership if data being accessed is owned by the variable used to access it
1742+ /// (or if closure attempts to move data that it doesn’t own).
1743+ /// Note: When taking ownership, only capture data found on the stack.
1744+ fn adjust_for_move_closure < ' tcx > (
17421745 mut place : Place < ' tcx > ,
17431746 kind : ty:: UpvarCapture < ' tcx > ,
17441747) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
17451748 let contains_deref_of_ref = place. deref_tys ( ) . any ( |ty| ty. is_ref ( ) ) ;
1749+ let first_deref = place. projections . iter ( ) . position ( |proj| proj. kind == ProjectionKind :: Deref ) ;
1750+
17461751 match kind {
17471752 ty:: UpvarCapture :: ByRef ( ..) if contains_deref_of_ref => ( place, kind) ,
17481753
17491754 // If there's any Deref and the data needs to be moved into the closure body,
17501755 // or it's a Deref of a Box, truncate the path to the first deref
1751- _ if place. deref_tys ( ) . next ( ) . is_some ( ) => {
1752- let first_deref =
1753- place. projections . iter ( ) . position ( |proj| proj. kind == ProjectionKind :: Deref ) ;
1756+ _ if first_deref. is_some ( ) => {
17541757 let place = match first_deref {
17551758 Some ( idx) => {
17561759 place. projections . truncate ( idx) ;
@@ -1768,7 +1771,9 @@ fn process_for_move<'tcx>(
17681771 }
17691772}
17701773
1771- fn process_for_ref < ' tcx > (
1774+ /// Adjust closure capture just that if taking ownership of data, only move data
1775+ /// from enclosing stack frame.
1776+ fn adjust_for_non_move_closure < ' tcx > (
17721777 mut place : Place < ' tcx > ,
17731778 kind : ty:: UpvarCapture < ' tcx > ,
17741779) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
0 commit comments