@@ -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;
@@ -1447,7 +1476,8 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
1447
1476
tcx : TyCtxt < ' tcx > ,
1448
1477
param_env : ty:: ParamEnv < ' tcx > ,
1449
1478
place : & Place < ' tcx > ,
1450
- ) -> Place < ' tcx > {
1479
+ curr_borrow_kind : ty:: UpvarCapture < ' tcx > ,
1480
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1451
1481
let pos = place. projections . iter ( ) . enumerate ( ) . position ( |( i, p) | {
1452
1482
let ty = place. ty_before_projection ( i) ;
1453
1483
@@ -1478,13 +1508,13 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
1478
1508
}
1479
1509
} ) ;
1480
1510
1481
- let mut place = place. clone ( ) ;
1511
+ let place = place. clone ( ) ;
1482
1512
1483
1513
if let Some ( pos) = pos {
1484
- place. projections . truncate ( pos) ;
1514
+ truncate_place_to_len ( place, curr_borrow_kind, pos)
1515
+ } else {
1516
+ ( place, curr_borrow_kind)
1485
1517
}
1486
-
1487
- place
1488
1518
}
1489
1519
1490
1520
/// Returns a Ty that applies the specified capture kind on the provided capture Ty
@@ -1605,20 +1635,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
1605
1635
) ;
1606
1636
1607
1637
if let PlaceBase :: Upvar ( _) = place_with_id. place . base {
1608
- let mut borrow_kind = ty:: MutBorrow ;
1609
- for pointer_ty in place_with_id. place . deref_tys ( ) {
1610
- match pointer_ty. kind ( ) {
1611
- // Raw pointers don't inherit mutability.
1612
- ty:: RawPtr ( _) => return ,
1613
- // assignment to deref of an `&mut`
1614
- // borrowed pointer implies that the
1615
- // pointer itself must be unique, but not
1616
- // necessarily *mutable*
1617
- ty:: Ref ( .., hir:: Mutability :: Mut ) => borrow_kind = ty:: UniqueImmBorrow ,
1618
- _ => ( ) ,
1619
- }
1638
+ // Raw pointers don't inherit mutability
1639
+ if place_with_id. place . deref_tys ( ) . any ( ty:: TyS :: is_unsafe_ptr) {
1640
+ return ;
1620
1641
}
1621
- self . adjust_upvar_deref ( place_with_id, diag_expr_id, borrow_kind ) ;
1642
+ self . adjust_upvar_deref ( place_with_id, diag_expr_id, ty :: MutBorrow ) ;
1622
1643
}
1623
1644
}
1624
1645
@@ -1735,9 +1756,19 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1735
1756
if let PlaceBase :: Upvar ( _) = place. base {
1736
1757
// We need to restrict Fake Read precision to avoid fake reading unsafe code,
1737
1758
// such as deref of a raw pointer.
1738
- let place = restrict_capture_precision ( place) ;
1739
- let place =
1740
- restrict_repr_packed_field_ref_capture ( self . fcx . tcx , self . fcx . param_env , & place) ;
1759
+ let dummy_capture_kind = ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow {
1760
+ kind : ty:: BorrowKind :: ImmBorrow ,
1761
+ region : & ty:: ReErased ,
1762
+ } ) ;
1763
+
1764
+ let ( place, _) = restrict_capture_precision ( place, dummy_capture_kind) ;
1765
+
1766
+ let ( place, _) = restrict_repr_packed_field_ref_capture (
1767
+ self . fcx . tcx ,
1768
+ self . fcx . param_env ,
1769
+ & place,
1770
+ dummy_capture_kind,
1771
+ ) ;
1741
1772
self . fake_reads . push ( ( place, cause, diag_expr_id) ) ;
1742
1773
}
1743
1774
}
@@ -1763,13 +1794,18 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1763
1794
place_with_id, diag_expr_id, bk
1764
1795
) ;
1765
1796
1797
+ // The region here will get discarded/ignored
1798
+ let dummy_capture_kind =
1799
+ ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow { kind : bk, region : & ty:: ReErased } ) ;
1800
+
1766
1801
// We only want repr packed restriction to be applied to reading references into a packed
1767
1802
// struct, and not when the data is being moved. Therefore we call this method here instead
1768
1803
// of in `restrict_capture_precision`.
1769
- let place = restrict_repr_packed_field_ref_capture (
1804
+ let ( place, updated_kind ) = restrict_repr_packed_field_ref_capture (
1770
1805
self . fcx . tcx ,
1771
1806
self . fcx . param_env ,
1772
1807
& place_with_id. place ,
1808
+ dummy_capture_kind,
1773
1809
) ;
1774
1810
1775
1811
let place_with_id = PlaceWithHirId { place, ..* place_with_id } ;
@@ -1778,14 +1814,19 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1778
1814
self . init_capture_info_for_place ( & place_with_id, diag_expr_id) ;
1779
1815
}
1780
1816
1781
- match bk {
1782
- ty:: ImmBorrow => { }
1783
- ty:: UniqueImmBorrow => {
1784
- self . adjust_upvar_borrow_kind_for_unique ( & place_with_id, diag_expr_id) ;
1785
- }
1786
- ty:: MutBorrow => {
1787
- self . adjust_upvar_borrow_kind_for_mut ( & place_with_id, diag_expr_id) ;
1788
- }
1817
+ match updated_kind {
1818
+ ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow { kind, .. } ) => match kind {
1819
+ ty:: ImmBorrow => { }
1820
+ ty:: UniqueImmBorrow => {
1821
+ self . adjust_upvar_borrow_kind_for_unique ( & place_with_id, diag_expr_id) ;
1822
+ }
1823
+ ty:: MutBorrow => {
1824
+ self . adjust_upvar_borrow_kind_for_mut ( & place_with_id, diag_expr_id) ;
1825
+ }
1826
+ } ,
1827
+
1828
+ // Just truncating the place will never cause capture kind to be updated to ByValue
1829
+ ty:: UpvarCapture :: ByValue ( ..) => unreachable ! ( ) ,
1789
1830
}
1790
1831
}
1791
1832
@@ -1799,72 +1840,73 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
1799
1840
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
1800
1841
/// them completely.
1801
1842
/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
1802
- fn restrict_precision_for_unsafe ( mut place : Place < ' tcx > ) -> Place < ' tcx > {
1843
+ fn restrict_precision_for_unsafe (
1844
+ place : Place < ' tcx > ,
1845
+ curr_mode : ty:: UpvarCapture < ' tcx > ,
1846
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1803
1847
if place. projections . is_empty ( ) {
1804
1848
// Nothing to do here
1805
- return place;
1849
+ return ( place, curr_mode ) ;
1806
1850
}
1807
1851
1808
1852
if place. base_ty . is_unsafe_ptr ( ) {
1809
- place. projections . truncate ( 0 ) ;
1810
- return place;
1853
+ return truncate_place_to_len ( place, curr_mode, 0 ) ;
1811
1854
}
1812
1855
1813
1856
if place. base_ty . is_union ( ) {
1814
- place. projections . truncate ( 0 ) ;
1815
- return place;
1857
+ return truncate_place_to_len ( place, curr_mode, 0 ) ;
1816
1858
}
1817
1859
1818
1860
for ( i, proj) in place. projections . iter ( ) . enumerate ( ) {
1819
1861
if proj. ty . is_unsafe_ptr ( ) {
1820
1862
// Don't apply any projections on top of an unsafe ptr.
1821
- place. projections . truncate ( i + 1 ) ;
1822
- break ;
1863
+ return truncate_place_to_len ( place, curr_mode, i + 1 ) ;
1823
1864
}
1824
1865
1825
1866
if proj. ty . is_union ( ) {
1826
1867
// Don't capture preicse fields of a union.
1827
- place. projections . truncate ( i + 1 ) ;
1828
- break ;
1868
+ return truncate_place_to_len ( place, curr_mode, i + 1 ) ;
1829
1869
}
1830
1870
}
1831
1871
1832
- place
1872
+ ( place, curr_mode )
1833
1873
}
1834
1874
1835
1875
/// Truncate projections so that following rules are obeyed by the captured `place`:
1836
1876
/// - No Index projections are captured, since arrays are captured completely.
1837
1877
/// - No unsafe block is required to capture `place`
1838
- /// Truncate projections so that following rules are obeyed by the captured `place`:
1839
- fn restrict_capture_precision < ' tcx > ( mut place : Place < ' tcx > ) -> Place < ' tcx > {
1840
- place = restrict_precision_for_unsafe ( place) ;
1878
+ /// Returns the truncated place and updated cature mode.
1879
+ fn restrict_capture_precision < ' tcx > (
1880
+ place : Place < ' tcx > ,
1881
+ curr_mode : ty:: UpvarCapture < ' tcx > ,
1882
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1883
+ let ( place, curr_mode) = restrict_precision_for_unsafe ( place, curr_mode) ;
1841
1884
1842
1885
if place. projections . is_empty ( ) {
1843
1886
// Nothing to do here
1844
- return place;
1887
+ return ( place, curr_mode ) ;
1845
1888
}
1846
1889
1847
1890
for ( i, proj) in place. projections . iter ( ) . enumerate ( ) {
1848
1891
match proj. kind {
1849
1892
ProjectionKind :: Index => {
1850
1893
// Arrays are completely captured, so we drop Index projections
1851
- place. projections . truncate ( i) ;
1852
- break ;
1894
+ return truncate_place_to_len ( place, curr_mode, i) ;
1853
1895
}
1854
1896
ProjectionKind :: Deref => { }
1855
1897
ProjectionKind :: Field ( ..) => { } // ignore
1856
1898
ProjectionKind :: Subslice => { } // We never capture this
1857
1899
}
1858
1900
}
1859
1901
1860
- place
1902
+ return ( place, curr_mode ) ;
1861
1903
}
1862
1904
1863
1905
/// Take ownership if data being accessed is owned by the variable used to access it
1864
1906
/// (or if closure attempts to move data that it doesn’t own).
1865
1907
/// Note: When taking ownership, only capture data found on the stack.
1866
1908
fn adjust_for_move_closure < ' tcx > (
1867
- mut place : Place < ' tcx > ,
1909
+ place : Place < ' tcx > ,
1868
1910
kind : ty:: UpvarCapture < ' tcx > ,
1869
1911
) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1870
1912
let contains_deref_of_ref = place. deref_tys ( ) . any ( |ty| ty. is_ref ( ) ) ;
@@ -1878,7 +1920,7 @@ fn adjust_for_move_closure<'tcx>(
1878
1920
_ if first_deref. is_some ( ) => {
1879
1921
let place = match first_deref {
1880
1922
Some ( idx) => {
1881
- place. projections . truncate ( idx) ;
1923
+ let ( place, _ ) = truncate_place_to_len ( place , kind , idx) ;
1882
1924
place
1883
1925
}
1884
1926
None => place,
@@ -1896,8 +1938,8 @@ fn adjust_for_move_closure<'tcx>(
1896
1938
/// Adjust closure capture just that if taking ownership of data, only move data
1897
1939
/// from enclosing stack frame.
1898
1940
fn adjust_for_non_move_closure < ' tcx > (
1899
- mut place : Place < ' tcx > ,
1900
- kind : ty:: UpvarCapture < ' tcx > ,
1941
+ place : Place < ' tcx > ,
1942
+ mut kind : ty:: UpvarCapture < ' tcx > ,
1901
1943
) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
1902
1944
let contains_deref =
1903
1945
place. projections . iter ( ) . position ( |proj| proj. kind == ProjectionKind :: Deref ) ;
@@ -1906,7 +1948,9 @@ fn adjust_for_non_move_closure<'tcx>(
1906
1948
ty:: UpvarCapture :: ByValue ( ..) if contains_deref. is_some ( ) => {
1907
1949
let place = match contains_deref {
1908
1950
Some ( idx) => {
1909
- place. projections . truncate ( idx) ;
1951
+ let ( place, new_kind) = truncate_place_to_len ( place, kind, idx) ;
1952
+
1953
+ kind = new_kind;
1910
1954
place
1911
1955
}
1912
1956
// Because of the if guard on the match on `kind`, we should never get here.
@@ -2107,6 +2151,49 @@ fn determine_capture_info(
2107
2151
}
2108
2152
}
2109
2153
2154
+ /// Truncates `place` to have up to `len` projections.
2155
+ /// `curr_mode` is the current required capture kind for the place.
2156
+ /// Returns the truncated `place` and the updated required capture kind.
2157
+ ///
2158
+ /// Note: Capture kind changes from `MutBorrow` to `UniqueImmBorrow` if the truncated part of the `place`
2159
+ /// contained `Deref` of `&mut`.
2160
+ fn truncate_place_to_len (
2161
+ mut place : Place < ' tcx > ,
2162
+ curr_mode : ty:: UpvarCapture < ' tcx > ,
2163
+ len : usize ,
2164
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
2165
+ let is_mut_ref = |ty : Ty < ' _ > | matches ! ( ty. kind( ) , ty:: Ref ( .., hir:: Mutability :: Mut ) ) ;
2166
+
2167
+ let mut capture_kind = curr_mode;
2168
+
2169
+ // If the truncated part of the place contains `Deref` of a `&mut` then convert MutBorrow ->
2170
+ // UniqueImmBorrow
2171
+ // Note that if the place contained Deref of a raw pointer it would've not been MutBorrow, so
2172
+ // we don't need to worry about that case here.
2173
+ match curr_mode {
2174
+ ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow { kind : ty:: BorrowKind :: MutBorrow , region } ) => {
2175
+ for i in len..place. projections . len ( ) {
2176
+ if place. projections [ i] . kind == ProjectionKind :: Deref
2177
+ && is_mut_ref ( place. ty_before_projection ( i) )
2178
+ {
2179
+ capture_kind = ty:: UpvarCapture :: ByRef ( ty:: UpvarBorrow {
2180
+ kind : ty:: BorrowKind :: UniqueImmBorrow ,
2181
+ region,
2182
+ } ) ;
2183
+ break ;
2184
+ }
2185
+ }
2186
+ }
2187
+
2188
+ ty:: UpvarCapture :: ByRef ( ..) => { }
2189
+ ty:: UpvarCapture :: ByValue ( ..) => { }
2190
+ }
2191
+
2192
+ place. projections . truncate ( len) ;
2193
+
2194
+ ( place, capture_kind)
2195
+ }
2196
+
2110
2197
/// Determines the Ancestry relationship of Place A relative to Place B
2111
2198
///
2112
2199
/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B
@@ -2168,7 +2255,10 @@ fn determine_place_ancestry_relation(
2168
2255
/// // it is constrained to `'a`
2169
2256
/// }
2170
2257
/// ```
2171
- fn truncate_capture_for_optimization < ' tcx > ( place : & Place < ' tcx > ) -> Place < ' tcx > {
2258
+ fn truncate_capture_for_optimization < ' tcx > (
2259
+ place : Place < ' tcx > ,
2260
+ curr_mode : ty:: UpvarCapture < ' tcx > ,
2261
+ ) -> ( Place < ' tcx > , ty:: UpvarCapture < ' tcx > ) {
2172
2262
let is_shared_ref = |ty : Ty < ' _ > | matches ! ( ty. kind( ) , ty:: Ref ( .., hir:: Mutability :: Not ) ) ;
2173
2263
2174
2264
// Find the right-most deref (if any). All the projections that come after this
@@ -2179,9 +2269,9 @@ fn truncate_capture_for_optimization<'tcx>(place: &Place<'tcx>) -> Place<'tcx> {
2179
2269
match idx {
2180
2270
// If that pointer is a shared reference, then we don't need those fields.
2181
2271
Some ( idx) if is_shared_ref ( place. ty_before_projection ( idx) ) => {
2182
- Place { projections : place . projections [ 0 ..= idx] . to_vec ( ) , ..place . clone ( ) }
2272
+ truncate_place_to_len ( place , curr_mode , idx + 1 )
2183
2273
}
2184
- None | Some ( _) => place . clone ( ) ,
2274
+ None | Some ( _) => ( place , curr_mode ) ,
2185
2275
}
2186
2276
}
2187
2277
0 commit comments