@@ -16,6 +16,8 @@ use rustc_target::abi::LayoutOf;
16
16
pub fn non_ssa_locals < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
17
17
fx : & FunctionCx < ' a , ' tcx , Bx > ,
18
18
) -> BitSet < mir:: Local > {
19
+ trace ! ( "non_ssa_locals({:?})" , fx. instance. def_id( ) ) ;
20
+
19
21
let mir = fx. mir ;
20
22
let mut analyzer = LocalAnalyzer :: new ( fx) ;
21
23
@@ -40,21 +42,13 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
40
42
analyzer. non_ssa_locals
41
43
}
42
44
43
- #[ derive( Default , PartialEq , Eq ) ]
44
- struct PlaceInfo {
45
- has_disqualifying_projection : bool ,
46
- has_deref_projection : bool ,
47
- }
48
-
49
45
struct LocalAnalyzer < ' mir , ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > {
50
46
fx : & ' mir FunctionCx < ' a , ' tcx , Bx > ,
51
47
dominators : Dominators < mir:: BasicBlock > ,
52
48
non_ssa_locals : BitSet < mir:: Local > ,
53
49
54
50
/// The location of the first visited direct assignment to each local.
55
51
first_assignment : IndexVec < mir:: Local , Option < Location > > ,
56
-
57
- place_info : PlaceInfo ,
58
52
}
59
53
60
54
impl < Bx : BuilderMethods < ' a , ' tcx > > LocalAnalyzer < ' mir , ' a , ' tcx , Bx > {
@@ -65,7 +59,6 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
65
59
dominators,
66
60
non_ssa_locals : BitSet :: new_empty ( fx. mir . local_decls . len ( ) ) ,
67
61
first_assignment : IndexVec :: from_elem ( None , & fx. mir . local_decls ) ,
68
- place_info : PlaceInfo :: default ( ) ,
69
62
} ;
70
63
71
64
// Arguments get assigned to by means of the function being called
@@ -146,7 +139,12 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
146
139
self . super_terminator ( terminator, location) ;
147
140
}
148
141
149
- fn visit_place ( & mut self , place : & mir:: Place < ' tcx > , context : PlaceContext , location : Location ) {
142
+ fn visit_place (
143
+ & mut self ,
144
+ place : & mir:: Place < ' tcx > ,
145
+ mut context : PlaceContext ,
146
+ location : Location ,
147
+ ) {
150
148
debug ! ( "visit_place(place={:?}, context={:?})" , place, context) ;
151
149
152
150
// Except for `VarDebugInfo`, non-uses do not force locals onto the stack.
@@ -158,7 +156,8 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
158
156
159
157
let mir:: Place { local, projection } = * place;
160
158
161
- // Reads from ZSTs do not require memory accesses.
159
+ // Reads from ZSTs do not require memory accesses and do not count when determining what
160
+ // needs to live on the stack.
162
161
if is_consume ( context) {
163
162
let ty = place. ty ( self . fx . mir , self . fx . cx . tcx ( ) ) . ty ;
164
163
let ty = self . fx . monomorphize ( & ty) ;
@@ -168,24 +167,40 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
168
167
}
169
168
}
170
169
171
- assert ! ( self . place_info == PlaceInfo :: default ( ) , "`visit_place` should not recurse" ) ;
172
- self . visit_projection ( local, projection, context, location) ;
170
+ let mut has_disqualifying_projection = false ;
173
171
174
- let PlaceInfo { has_disqualifying_projection, has_deref_projection } =
175
- std:: mem:: take ( & mut self . place_info ) ;
172
+ let mut projection: & [ _ ] = projection. as_ref ( ) ;
173
+ while let [ ref proj_base @ .., elem] = * projection {
174
+ projection = proj_base;
175
+ self . super_projection_elem ( local, proj_base, elem, context, location) ;
176
+
177
+ // Projections like `(*x)[12]` are allowed but not `*(x[12])`, since a `Deref` of a
178
+ // local acts like a `Copy` of that local.
179
+ if let mir:: PlaceElem :: Deref = elem {
180
+ has_disqualifying_projection = false ;
181
+ context = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ;
182
+ continue ;
183
+ }
184
+
185
+ // Ignoring `Deref`s, the only allowed projections are reads of scalar fields.
186
+ if is_consume ( context) && matches ! ( elem, mir:: ProjectionElem :: Field ( ..) ) {
187
+ let base_ty = mir:: Place :: ty_from ( local, proj_base, self . fx . mir , self . fx . cx . tcx ( ) ) ;
188
+ let base_ty = self . fx . monomorphize ( & base_ty) ;
189
+ let span = self . fx . mir . local_decls [ local] . source_info . span ;
190
+ let layout = self . fx . cx . spanned_layout_of ( base_ty. ty , span) ;
191
+
192
+ if !ty_requires_alloca ( self . fx , layout) {
193
+ continue ;
194
+ }
195
+ }
196
+
197
+ has_disqualifying_projection = true ;
198
+ }
176
199
177
200
if has_disqualifying_projection {
178
201
self . not_ssa ( local) ;
179
- return ;
180
202
}
181
203
182
- // Treat a `Deref` of a local as a `Copy` of that local.
183
- let context = if has_deref_projection {
184
- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy )
185
- } else {
186
- context
187
- } ;
188
-
189
204
self . visit_local ( & local, context, location) ;
190
205
}
191
206
@@ -249,41 +264,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
249
264
}
250
265
}
251
266
252
- fn visit_projection_elem (
253
- & mut self ,
254
- local : mir:: Local ,
255
- proj_base : & [ mir:: PlaceElem < ' tcx > ] ,
256
- elem : mir:: PlaceElem < ' tcx > ,
257
- context : PlaceContext ,
258
- location : Location ,
259
- ) {
260
- self . super_projection_elem ( local, proj_base, elem, context, location) ;
261
-
262
- // Projections like `(*x)[12]` are allowed but not `*(x[12])`.
263
- if let mir:: PlaceElem :: Deref = elem {
264
- self . place_info . has_disqualifying_projection = false ;
265
- self . place_info . has_deref_projection = true ;
266
- return ;
267
- }
268
-
269
- if !is_consume ( context) {
270
- self . place_info . has_disqualifying_projection = true ;
271
- return ;
272
- }
273
-
274
- if let mir:: ProjectionElem :: Field ( ..) = elem {
275
- let base_ty = mir:: Place :: ty_from ( local, proj_base, self . fx . mir , self . fx . cx . tcx ( ) ) ;
276
- let base_ty = self . fx . monomorphize ( & base_ty) ;
277
- let span = self . fx . mir . local_decls [ local] . source_info . span ;
278
- let layout = self . fx . cx . spanned_layout_of ( base_ty. ty , span) ;
279
- if !ty_requires_alloca ( self . fx , layout) {
280
- return ;
281
- }
282
- }
283
-
284
- self . place_info . has_disqualifying_projection = true ;
285
- }
286
-
287
267
fn visit_var_debug_info ( & mut self , var_debug_info : & mir:: VarDebugInfo < ' tcx > ) {
288
268
// Indirect debuginfo requires going through memory, that only
289
269
// the debugger accesses, following our emitted DWARF pointer ops.
0 commit comments