@@ -350,9 +350,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
350
350
351
351
for ( place, mut capture_info) in capture_information {
352
352
// Apply rules for safety before inferring closure kind
353
- let place = restrict_capture_precision ( place) ;
353
+ let ( place, capture_kind) =
354
+ restrict_capture_precision ( place, capture_info. capture_kind ) ;
355
+ capture_info. capture_kind = capture_kind;
354
356
355
- let place = truncate_capture_for_optimization ( & place) ;
357
+ let ( place, capture_kind) =
358
+ truncate_capture_for_optimization ( place, capture_info. capture_kind ) ;
359
+ capture_info. capture_kind = capture_kind;
356
360
357
361
let usage_span = if let Some ( usage_expr) = capture_info. path_expr_id {
358
362
self . tcx . hir ( ) . span ( usage_expr)
@@ -520,8 +524,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
520
524
// current place is ancestor of possible_descendant
521
525
PlaceAncestryRelation :: Ancestor => {
522
526
descendant_found = true ;
527
+
528
+ let mut possible_descendant = possible_descendant. clone ( ) ;
523
529
let backup_path_expr_id = updated_capture_info. path_expr_id ;
524
530
531
+ // Truncate the descendant (already in min_captures) to be same as the ancestor to handle any
532
+ // possible change in capture mode.
533
+ let ( _, descendant_capture_kind) = truncate_place_to_len (
534
+ possible_descendant. place ,
535
+ possible_descendant. info . capture_kind ,
536
+ place. projections . len ( ) ,
537
+ ) ;
538
+
539
+ possible_descendant. info . capture_kind = descendant_capture_kind;
540
+
525
541
updated_capture_info =
526
542
determine_capture_info ( updated_capture_info, possible_descendant. info ) ;
527
543
@@ -542,8 +558,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
542
558
PlaceAncestryRelation :: Descendant => {
543
559
ancestor_found = true ;
544
560
let backup_path_expr_id = possible_ancestor. info . path_expr_id ;
545
- possible_ancestor. info =
546
- determine_capture_info ( possible_ancestor. info , capture_info) ;
561
+
562
+ // Truncate the descendant (current place) to be same as the ancestor to handle any
563
+ // possible change in capture mode.
564
+ let ( _, descendant_capture_kind) = truncate_place_to_len (
565
+ place. clone ( ) ,
566
+ updated_capture_info. capture_kind ,
567
+ possible_ancestor. place . projections . len ( ) ,
568
+ ) ;
569
+
570
+ updated_capture_info. capture_kind = descendant_capture_kind;
571
+
572
+ possible_ancestor. info = determine_capture_info (
573
+ possible_ancestor. info ,
574
+ updated_capture_info,
575
+ ) ;
547
576
548
577
// we need to keep the ancestor's `path_expr_id`
549
578
possible_ancestor. info . path_expr_id = backup_path_expr_id;
@@ -1412,7 +1441,8 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
1412
1441
tcx : TyCtxt < ' tcx > ,
1413
1442
param_env : ty:: ParamEnv < ' tcx > ,
1414
1443
place : & Place < ' tcx > ,
1415
- ) -> Place < ' tcx > {
1444
+ curr_borrow_kind : ty:: UpvarCapture < ' tcx > ,
1445
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1416
1446
let pos = place. projections . iter ( ) . enumerate ( ) . position ( |( i, p) | {
1417
1447
let ty = place. ty_before_projection ( i) ;
1418
1448
@@ -1443,13 +1473,13 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
1443
1473
}
1444
1474
} ) ;
1445
1475
1446
- let mut place = place. clone ( ) ;
1476
+ let place = place. clone ( ) ;
1447
1477
1448
1478
if let Some ( pos) = pos {
1449
- place. projections . truncate ( pos) ;
1479
+ truncate_place_to_len ( place, curr_borrow_kind, pos)
1480
+ } else {
1481
+ ( place, curr_borrow_kind)
1450
1482
}
1451
-
1452
- place
1453
1483
}
1454
1484
1455
1485
/// Returns a Ty that applies the specified capture kind on the provided capture Ty
@@ -1570,20 +1600,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
1570
1600
) ;
1571
1601
1572
1602
if let PlaceBase :: Upvar ( _) = place_with_id. place . base {
1573
- let mut borrow_kind = ty:: MutBorrow ;
1574
- for pointer_ty in place_with_id. place . deref_tys ( ) {
1575
- match pointer_ty. kind ( ) {
1576
- // Raw pointers don't inherit mutability.
1577
- ty:: RawPtr ( _) => return ,
1578
- // assignment to deref of an `&mut`
1579
- // borrowed pointer implies that the
1580
- // pointer itself must be unique, but not
1581
- // necessarily *mutable*
1582
- ty:: Ref ( .., hir:: Mutability :: Mut ) => borrow_kind = ty:: UniqueImmBorrow ,
1583
- _ => ( ) ,
1584
- }
1603
+ // Raw pointers don't inherit mutability
1604
+ if place_with_id. place . deref_tys ( ) . any ( ty:: TyS :: is_unsafe_ptr) {
1605
+ return ;
1585
1606
}
1586
- self . adjust_upvar_deref ( place_with_id, diag_expr_id, borrow_kind ) ;
1607
+ self . adjust_upvar_deref ( place_with_id, diag_expr_id, ty :: MutBorrow ) ;
1587
1608
}
1588
1609
}
1589
1610
@@ -1700,9 +1721,19 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1700
1721
if let PlaceBase :: Upvar ( _) = place. base {
1701
1722
// We need to restrict Fake Read precision to avoid fake reading unsafe code,
1702
1723
// such as deref of a raw pointer.
1703
- let place = restrict_capture_precision ( place) ;
1704
- let place =
1705
- restrict_repr_packed_field_ref_capture ( self . fcx . tcx , self . fcx . param_env , & place) ;
1724
+ let dummy_capture_kind = ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow {
1725
+ kind : ty:: BorrowKind :: ImmBorrow ,
1726
+ region : & ty:: ReErased ,
1727
+ } ) ;
1728
+
1729
+ let ( place, _) = restrict_capture_precision ( place, dummy_capture_kind) ;
1730
+
1731
+ let ( place, _) = restrict_repr_packed_field_ref_capture (
1732
+ self . fcx . tcx ,
1733
+ self . fcx . param_env ,
1734
+ & place,
1735
+ dummy_capture_kind,
1736
+ ) ;
1706
1737
self . fake_reads . push ( ( place, cause, diag_expr_id) ) ;
1707
1738
}
1708
1739
}
@@ -1728,13 +1759,18 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1728
1759
place_with_id, diag_expr_id, bk
1729
1760
) ;
1730
1761
1762
+ // The region here will get discarded/ignored
1763
+ let dummy_capture_kind =
1764
+ ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow { kind : bk, region : & ty:: ReErased } ) ;
1765
+
1731
1766
// We only want repr packed restriction to be applied to reading references into a packed
1732
1767
// struct, and not when the data is being moved. Therefore we call this method here instead
1733
1768
// of in `restrict_capture_precision`.
1734
- let place = restrict_repr_packed_field_ref_capture (
1769
+ let ( place, updated_kind ) = restrict_repr_packed_field_ref_capture (
1735
1770
self . fcx . tcx ,
1736
1771
self . fcx . param_env ,
1737
1772
& place_with_id. place ,
1773
+ dummy_capture_kind,
1738
1774
) ;
1739
1775
1740
1776
let place_with_id = PlaceWithHirId { place, ..* place_with_id } ;
@@ -1743,14 +1779,19 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1743
1779
self . init_capture_info_for_place ( & place_with_id, diag_expr_id) ;
1744
1780
}
1745
1781
1746
- match bk {
1747
- ty:: ImmBorrow => { }
1748
- ty:: UniqueImmBorrow => {
1749
- self . adjust_upvar_borrow_kind_for_unique ( & place_with_id, diag_expr_id) ;
1750
- }
1751
- ty:: MutBorrow => {
1752
- self . adjust_upvar_borrow_kind_for_mut ( & place_with_id, diag_expr_id) ;
1753
- }
1782
+ match updated_kind {
1783
+ ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow { kind, .. } ) => match kind {
1784
+ ty:: ImmBorrow => { }
1785
+ ty:: UniqueImmBorrow => {
1786
+ self . adjust_upvar_borrow_kind_for_unique ( & place_with_id, diag_expr_id) ;
1787
+ }
1788
+ ty:: MutBorrow => {
1789
+ self . adjust_upvar_borrow_kind_for_mut ( & place_with_id, diag_expr_id) ;
1790
+ }
1791
+ } ,
1792
+
1793
+ // Just truncating the place will never cause capture kind to be updated to ByValue
1794
+ ty:: UpvarCapture :: ByValue ( ..) => unreachable ! ( ) ,
1754
1795
}
1755
1796
}
1756
1797
@@ -1764,72 +1805,73 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1764
1805
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
1765
1806
/// them completely.
1766
1807
/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
1767
- fn restrict_precision_for_unsafe ( mut place : Place < ' tcx > ) -> Place < ' tcx > {
1808
+ fn restrict_precision_for_unsafe (
1809
+ place : Place < ' tcx > ,
1810
+ curr_mode : ty:: UpvarCapture < ' tcx > ,
1811
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1768
1812
if place. projections . is_empty ( ) {
1769
1813
// Nothing to do here
1770
- return place;
1814
+ return ( place, curr_mode ) ;
1771
1815
}
1772
1816
1773
1817
if place. base_ty . is_unsafe_ptr ( ) {
1774
- place. projections . truncate ( 0 ) ;
1775
- return place;
1818
+ return truncate_place_to_len ( place, curr_mode, 0 ) ;
1776
1819
}
1777
1820
1778
1821
if place. base_ty . is_union ( ) {
1779
- place. projections . truncate ( 0 ) ;
1780
- return place;
1822
+ return truncate_place_to_len ( place, curr_mode, 0 ) ;
1781
1823
}
1782
1824
1783
1825
for ( i, proj) in place. projections . iter ( ) . enumerate ( ) {
1784
1826
if proj. ty . is_unsafe_ptr ( ) {
1785
1827
// Don't apply any projections on top of an unsafe ptr.
1786
- place. projections . truncate ( i + 1 ) ;
1787
- break ;
1828
+ return truncate_place_to_len ( place, curr_mode, i + 1 ) ;
1788
1829
}
1789
1830
1790
1831
if proj. ty . is_union ( ) {
1791
1832
// Don't capture preicse fields of a union.
1792
- place. projections . truncate ( i + 1 ) ;
1793
- break ;
1833
+ return truncate_place_to_len ( place, curr_mode, i + 1 ) ;
1794
1834
}
1795
1835
}
1796
1836
1797
- place
1837
+ ( place, curr_mode )
1798
1838
}
1799
1839
1800
1840
/// Truncate projections so that following rules are obeyed by the captured `place`:
1801
1841
/// - No Index projections are captured, since arrays are captured completely.
1802
1842
/// - No unsafe block is required to capture `place`
1803
- /// Truncate projections so that following rules are obeyed by the captured `place`:
1804
- fn restrict_capture_precision < ' tcx > ( mut place : Place < ' tcx > ) -> Place < ' tcx > {
1805
- place = restrict_precision_for_unsafe ( place) ;
1843
+ /// Returns the truncated place and updated cature mode.
1844
+ fn restrict_capture_precision < ' tcx > (
1845
+ place : Place < ' tcx > ,
1846
+ curr_mode : ty:: UpvarCapture < ' tcx > ,
1847
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1848
+ let ( place, curr_mode) = restrict_precision_for_unsafe ( place, curr_mode) ;
1806
1849
1807
1850
if place. projections . is_empty ( ) {
1808
1851
// Nothing to do here
1809
- return place;
1852
+ return ( place, curr_mode ) ;
1810
1853
}
1811
1854
1812
1855
for ( i, proj) in place. projections . iter ( ) . enumerate ( ) {
1813
1856
match proj. kind {
1814
1857
ProjectionKind :: Index => {
1815
1858
// Arrays are completely captured, so we drop Index projections
1816
- place. projections . truncate ( i) ;
1817
- break ;
1859
+ return truncate_place_to_len ( place, curr_mode, i) ;
1818
1860
}
1819
1861
ProjectionKind :: Deref => { }
1820
1862
ProjectionKind :: Field ( ..) => { } // ignore
1821
1863
ProjectionKind :: Subslice => { } // We never capture this
1822
1864
}
1823
1865
}
1824
1866
1825
- place
1867
+ return ( place, curr_mode ) ;
1826
1868
}
1827
1869
1828
1870
/// Take ownership if data being accessed is owned by the variable used to access it
1829
1871
/// (or if closure attempts to move data that it doesn’t own).
1830
1872
/// Note: When taking ownership, only capture data found on the stack.
1831
1873
fn adjust_for_move_closure < ' tcx > (
1832
- mut place : Place < ' tcx > ,
1874
+ place : Place < ' tcx > ,
1833
1875
kind : ty:: UpvarCapture < ' tcx > ,
1834
1876
) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1835
1877
let contains_deref_of_ref = place. deref_tys ( ) . any ( |ty| ty. is_ref ( ) ) ;
@@ -1843,7 +1885,7 @@ fn adjust_for_move_closure<'tcx>(
1843
1885
_ if first_deref. is_some ( ) => {
1844
1886
let place = match first_deref {
1845
1887
Some ( idx) => {
1846
- place. projections . truncate ( idx) ;
1888
+ let ( place, _ ) = truncate_place_to_len ( place , kind , idx) ;
1847
1889
place
1848
1890
}
1849
1891
None => place,
@@ -1861,8 +1903,8 @@ fn adjust_for_move_closure<'tcx>(
1861
1903
/// Adjust closure capture just that if taking ownership of data, only move data
1862
1904
/// from enclosing stack frame.
1863
1905
fn adjust_for_non_move_closure < ' tcx > (
1864
- mut place : Place < ' tcx > ,
1865
- kind : ty:: UpvarCapture < ' tcx > ,
1906
+ place : Place < ' tcx > ,
1907
+ mut kind : ty:: UpvarCapture < ' tcx > ,
1866
1908
) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1867
1909
let contains_deref =
1868
1910
place. projections . iter ( ) . position ( |proj| proj. kind == ProjectionKind :: Deref ) ;
@@ -1871,7 +1913,9 @@ fn adjust_for_non_move_closure<'tcx>(
1871
1913
ty:: UpvarCapture :: ByValue ( ..) if contains_deref. is_some ( ) => {
1872
1914
let place = match contains_deref {
1873
1915
Some ( idx) => {
1874
- place. projections . truncate ( idx) ;
1916
+ let ( place, new_kind) = truncate_place_to_len ( place, kind, idx) ;
1917
+
1918
+ kind = new_kind;
1875
1919
place
1876
1920
}
1877
1921
// Because of the if guard on the match on `kind`, we should never get here.
@@ -2072,6 +2116,49 @@ fn determine_capture_info(
2072
2116
}
2073
2117
}
2074
2118
2119
+ /// Truncates `place` to have up to `len` projections.
2120
+ /// `curr_mode` is the current required capture kind for the place.
2121
+ /// Returns the truncated `place` and the updated required capture kind.
2122
+ ///
2123
+ /// Note: Capture kind changes from `MutBorrow` to `UniqueImmBorrow` if the truncated part of the `place`
2124
+ /// contained `Deref` of `&mut`.
2125
+ fn truncate_place_to_len (
2126
+ mut place : Place < ' tcx > ,
2127
+ curr_mode : ty:: UpvarCapture < ' tcx > ,
2128
+ len : usize ,
2129
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
2130
+ let is_mut_ref = |ty : Ty < ' _ > | matches ! ( ty. kind( ) , ty:: Ref ( .., hir:: Mutability :: Mut ) ) ;
2131
+
2132
+ let mut capture_kind = curr_mode;
2133
+
2134
+ // If the truncated part of the place contains `Deref` of a `&mut` then convert MutBorrow ->
2135
+ // UniqueImmBorrow
2136
+ // Note that if the place contained Deref of a raw pointer it would've not been MutBorrow, so
2137
+ // we don't need to worry about that case here.
2138
+ match curr_mode {
2139
+ ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow { kind : ty:: BorrowKind :: MutBorrow , region } ) => {
2140
+ for i in len..place. projections . len ( ) {
2141
+ if place. projections [ i] . kind == ProjectionKind :: Deref
2142
+ && is_mut_ref ( place. ty_before_projection ( i) )
2143
+ {
2144
+ capture_kind = ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow {
2145
+ kind : ty:: BorrowKind :: UniqueImmBorrow ,
2146
+ region,
2147
+ } ) ;
2148
+ break ;
2149
+ }
2150
+ }
2151
+ }
2152
+
2153
+ ty:: UpvarCapture :: ByRef ( ..) => { }
2154
+ ty:: UpvarCapture :: ByValue ( ..) => { }
2155
+ }
2156
+
2157
+ place. projections . truncate ( len) ;
2158
+
2159
+ ( place, capture_kind)
2160
+ }
2161
+
2075
2162
/// Determines the Ancestry relationship of Place A relative to Place B
2076
2163
///
2077
2164
/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B
@@ -2133,7 +2220,10 @@ fn determine_place_ancestry_relation(
2133
2220
/// // it is constrained to `'a`
2134
2221
/// }
2135
2222
/// ```
2136
- fn truncate_capture_for_optimization < ' tcx > ( place : & Place < ' tcx > ) -> Place < ' tcx > {
2223
+ fn truncate_capture_for_optimization < ' tcx > (
2224
+ place : Place < ' tcx > ,
2225
+ curr_mode : ty:: UpvarCapture < ' tcx > ,
2226
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
2137
2227
let is_shared_ref = |ty : Ty < ' _ > | matches ! ( ty. kind( ) , ty:: Ref ( .., hir:: Mutability :: Not ) ) ;
2138
2228
2139
2229
// Find the right-most deref (if any). All the projections that come after this
@@ -2144,9 +2234,9 @@ fn truncate_capture_for_optimization<'tcx>(place: &Place<'tcx>) -> Place<'tcx> {
2144
2234
match idx {
2145
2235
// If that pointer is a shared reference, then we don't need those fields.
2146
2236
Some ( idx) if is_shared_ref ( place. ty_before_projection ( idx) ) => {
2147
- Place { projections : place . projections [ 0 ..= idx] . to_vec ( ) , ..place . clone ( ) }
2237
+ truncate_place_to_len ( place , curr_mode , idx + 1 )
2148
2238
}
2149
- None | Some ( _) => place . clone ( ) ,
2239
+ None | Some ( _) => ( place , curr_mode ) ,
2150
2240
}
2151
2241
}
2152
2242
0 commit comments