@@ -148,9 +148,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
148
148
fcx : self ,
149
149
closure_def_id,
150
150
closure_span : span,
151
- capture_clause,
152
- _current_closure_kind : ty:: ClosureKind :: LATTICE_BOTTOM ,
153
- _current_origin : None ,
154
151
capture_information : Default :: default ( ) ,
155
152
fake_reads : Default :: default ( ) ,
156
153
} ;
@@ -309,6 +306,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
309
306
. collect ( )
310
307
}
311
308
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.
312
324
fn process_collected_capture_information (
313
325
& self ,
314
326
capture_clause : hir:: CaptureBy ,
@@ -320,7 +332,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
320
332
let mut origin: Option < ( Span , Place < ' tcx > ) > = None ;
321
333
322
334
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
+
324
338
let usage_span = if let Some ( usage_expr) = capture_info. path_expr_id {
325
339
self . tcx . hir ( ) . span ( usage_expr)
326
340
} else {
@@ -356,8 +370,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
356
370
origin = updated. 1 ;
357
371
358
372
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
+ }
361
377
} ;
362
378
363
379
capture_info. capture_kind = capture_kind;
@@ -1386,20 +1402,6 @@ struct InferBorrowKind<'a, 'tcx> {
1386
1402
1387
1403
closure_span : Span ,
1388
1404
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
-
1403
1405
/// For each Place that is captured by the closure, we track the minimal kind of
1404
1406
/// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
1405
1407
///
@@ -1442,7 +1444,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
1442
1444
place_with_id, diag_expr_id, mode
1443
1445
) ;
1444
1446
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.
1446
1449
match mode {
1447
1450
euv:: ConsumeMode :: Copy => return ,
1448
1451
euv:: ConsumeMode :: Move => { }
@@ -1589,8 +1592,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
1589
1592
if let PlaceBase :: Upvar ( upvar_id) = place_with_id. place . base {
1590
1593
assert_eq ! ( self . closure_def_id. expect_local( ) , upvar_id. closure_expr_id) ;
1591
1594
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` .
1594
1597
let origin = UpvarRegion ( upvar_id, self . closure_span ) ;
1595
1598
let upvar_region = self . fcx . next_region_var ( origin) ;
1596
1599
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> {
1617
1620
if let PlaceBase :: Upvar ( _) = place. base {
1618
1621
// We need to restrict Fake Read precision to avoid fake reading unsafe code,
1619
1622
// such as deref of a raw pointer.
1620
- let place = restrict_capture_precision ( self . capture_clause , place) ;
1623
+ let place = restrict_capture_precision ( place) ;
1621
1624
let place =
1622
1625
restrict_repr_packed_field_ref_capture ( self . fcx . tcx , self . fcx . param_env , & place) ;
1623
1626
self . fake_reads . push ( ( place, cause, diag_expr_id) ) ;
@@ -1659,7 +1662,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1659
1662
) ;
1660
1663
1661
1664
// 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
1663
1666
// of in `restrict_capture_precision`.
1664
1667
let place = restrict_repr_packed_field_ref_capture (
1665
1668
self . fcx . tcx ,
@@ -1697,10 +1700,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1697
1700
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
1698
1701
/// them completely.
1699
1702
/// - 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 > {
1704
1704
if place. projections . is_empty ( ) {
1705
1705
// Nothing to do here
1706
1706
return place;
@@ -1738,19 +1738,22 @@ fn restrict_capture_precision<'tcx>(
1738
1738
place
1739
1739
}
1740
1740
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 > (
1742
1745
mut place : Place < ' tcx > ,
1743
1746
kind : ty:: UpvarCapture < ' tcx > ,
1744
1747
) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1745
1748
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
+
1746
1751
match kind {
1747
1752
ty:: UpvarCapture :: ByRef ( ..) if contains_deref_of_ref => ( place, kind) ,
1748
1753
1749
1754
// If there's any Deref and the data needs to be moved into the closure body,
1750
1755
// 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 ( ) => {
1754
1757
let place = match first_deref {
1755
1758
Some ( idx) => {
1756
1759
place. projections . truncate ( idx) ;
@@ -1768,7 +1771,9 @@ fn process_for_move<'tcx>(
1768
1771
}
1769
1772
}
1770
1773
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 > (
1772
1777
mut place : Place < ' tcx > ,
1773
1778
kind : ty:: UpvarCapture < ' tcx > ,
1774
1779
) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
0 commit comments