1
1
use rustc_index:: bit_set:: BitSet ;
2
- use rustc_middle:: mir:: visit:: Visitor ;
3
2
use rustc_middle:: mir:: * ;
3
+ use rustc_middle:: { mir:: visit:: Visitor , ty} ;
4
4
5
5
use crate :: { AnalysisDomain , GenKill , GenKillAnalysis } ;
6
6
@@ -12,11 +12,28 @@ use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
12
12
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
13
13
/// immovable coroutines.
14
14
#[ derive( Clone , Copy ) ]
15
- pub struct MaybeBorrowedLocals ;
15
+ pub struct MaybeBorrowedLocals {
16
+ upvar_start : Option < ( Local , usize ) > ,
17
+ }
16
18
17
19
impl MaybeBorrowedLocals {
20
+ /// `upvar_start` is to signal that upvars are treated as locals,
21
+ /// and locals greater than this value refers to upvars accessed
22
+ /// through the tuple `ty::CAPTURE_STRUCT_LOCAL`, aka. _1.
23
+ pub fn new ( upvar_start : Option < ( Local , usize ) > ) -> Self {
24
+ Self { upvar_start }
25
+ }
26
+
18
27
pub ( super ) fn transfer_function < ' a , T > ( & ' a self , trans : & ' a mut T ) -> TransferFunction < ' a , T > {
19
- TransferFunction { trans }
28
+ TransferFunction { trans, upvar_start : self . upvar_start }
29
+ }
30
+
31
+ pub fn domain_size ( & self , body : & Body < ' _ > ) -> usize {
32
+ if let Some ( ( start, len) ) = self . upvar_start {
33
+ start. as_usize ( ) + len
34
+ } else {
35
+ body. local_decls . len ( )
36
+ }
20
37
}
21
38
}
22
39
@@ -26,7 +43,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals {
26
43
27
44
fn bottom_value ( & self , body : & Body < ' tcx > ) -> Self :: Domain {
28
45
// bottom = unborrowed
29
- BitSet :: new_empty ( body . local_decls ( ) . len ( ) )
46
+ BitSet :: new_empty ( self . domain_size ( body ) )
30
47
}
31
48
32
49
fn initialize_start_block ( & self , _: & Body < ' tcx > , _: & mut Self :: Domain ) {
@@ -38,7 +55,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
38
55
type Idx = Local ;
39
56
40
57
fn domain_size ( & self , body : & Body < ' tcx > ) -> usize {
41
- body . local_decls . len ( )
58
+ self . domain_size ( body )
42
59
}
43
60
44
61
fn statement_effect (
@@ -72,6 +89,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
72
89
/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
73
90
pub ( super ) struct TransferFunction < ' a , T > {
74
91
trans : & ' a mut T ,
92
+ upvar_start : Option < ( Local , usize ) > ,
75
93
}
76
94
77
95
impl < ' tcx , T > Visitor < ' tcx > for TransferFunction < ' _ , T >
@@ -97,7 +115,20 @@ where
97
115
Rvalue :: AddressOf ( _, borrowed_place)
98
116
| Rvalue :: Ref ( _, BorrowKind :: Mut { .. } | BorrowKind :: Shared , borrowed_place) => {
99
117
if !borrowed_place. is_indirect ( ) {
100
- self . trans . gen ( borrowed_place. local ) ;
118
+ if borrowed_place. local == ty:: CAPTURE_STRUCT_LOCAL
119
+ && let Some ( ( upvar_start, nr_upvars) ) = self . upvar_start
120
+ {
121
+ match * * borrowed_place. projection {
122
+ [ ProjectionElem :: Field ( field, _) , ..]
123
+ if field. as_usize ( ) < nr_upvars =>
124
+ {
125
+ self . trans . gen ( upvar_start + field. as_usize ( ) )
126
+ }
127
+ _ => bug ! ( "unexpected upvar access" ) ,
128
+ }
129
+ } else {
130
+ self . trans . gen ( borrowed_place. local ) ;
131
+ }
101
132
}
102
133
}
103
134
@@ -132,7 +163,26 @@ where
132
163
//
133
164
// [#61069]: https://github.com/rust-lang/rust/pull/61069
134
165
if !dropped_place. is_indirect ( ) {
135
- self . trans . gen ( dropped_place. local ) ;
166
+ if dropped_place. local == ty:: CAPTURE_STRUCT_LOCAL
167
+ && let Some ( ( upvar_start, nr_upvars) ) = self . upvar_start
168
+ {
169
+ match * * dropped_place. projection {
170
+ [ ] => {
171
+ for field in 0 ..nr_upvars {
172
+ self . trans . gen ( upvar_start + field)
173
+ }
174
+ self . trans . gen ( dropped_place. local )
175
+ }
176
+ [ ProjectionElem :: Field ( field, _) , ..]
177
+ if field. as_usize ( ) < nr_upvars =>
178
+ {
179
+ self . trans . gen ( upvar_start + field. as_usize ( ) )
180
+ }
181
+ _ => bug ! ( "unexpected upvar access" ) ,
182
+ }
183
+ } else {
184
+ self . trans . gen ( dropped_place. local ) ;
185
+ }
136
186
}
137
187
}
138
188
@@ -169,6 +219,6 @@ pub fn borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
169
219
}
170
220
171
221
let mut borrowed = Borrowed ( BitSet :: new_empty ( body. local_decls . len ( ) ) ) ;
172
- TransferFunction { trans : & mut borrowed } . visit_body ( body) ;
222
+ TransferFunction { trans : & mut borrowed, upvar_start : None } . visit_body ( body) ;
173
223
borrowed. 0
174
224
}
0 commit comments