@@ -16,6 +16,8 @@ use rustc_target::abi::LayoutOf;
1616pub fn non_ssa_locals < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
1717 fx : & FunctionCx < ' a , ' tcx , Bx > ,
1818) -> BitSet < mir:: Local > {
19+ trace ! ( "non_ssa_locals({:?})" , fx. instance. def_id( ) ) ;
20+
1921 let mir = fx. mir ;
2022 let mut analyzer = LocalAnalyzer :: new ( fx) ;
2123
@@ -40,21 +42,13 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
4042 analyzer. non_ssa_locals
4143}
4244
43- #[ derive( Default , PartialEq , Eq ) ]
44- struct PlaceInfo {
45- has_disqualifying_projection : bool ,
46- has_deref_projection : bool ,
47- }
48-
4945struct LocalAnalyzer < ' mir , ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > {
5046 fx : & ' mir FunctionCx < ' a , ' tcx , Bx > ,
5147 dominators : Dominators < mir:: BasicBlock > ,
5248 non_ssa_locals : BitSet < mir:: Local > ,
5349
5450 /// The location of the first visited direct assignment to each local.
5551 first_assignment : IndexVec < mir:: Local , Option < Location > > ,
56-
57- place_info : PlaceInfo ,
5852}
5953
6054impl < Bx : BuilderMethods < ' a , ' tcx > > LocalAnalyzer < ' mir , ' a , ' tcx , Bx > {
@@ -65,7 +59,6 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
6559 dominators,
6660 non_ssa_locals : BitSet :: new_empty ( fx. mir . local_decls . len ( ) ) ,
6761 first_assignment : IndexVec :: from_elem ( None , & fx. mir . local_decls ) ,
68- place_info : PlaceInfo :: default ( ) ,
6962 } ;
7063
7164 // 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>
146139 self . super_terminator ( terminator, location) ;
147140 }
148141
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+ ) {
150148 debug ! ( "visit_place(place={:?}, context={:?})" , place, context) ;
151149
152150 // 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>
158156
159157 let mir:: Place { local, projection } = * place;
160158
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.
162161 if is_consume ( context) {
163162 let ty = place. ty ( self . fx . mir , self . fx . cx . tcx ( ) ) . ty ;
164163 let ty = self . fx . monomorphize ( & ty) ;
@@ -168,24 +167,40 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
168167 }
169168 }
170169
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 ;
173171
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+ }
176199
177200 if has_disqualifying_projection {
178201 self . not_ssa ( local) ;
179- return ;
180202 }
181203
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-
189204 self . visit_local ( & local, context, location) ;
190205 }
191206
@@ -249,41 +264,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
249264 }
250265 }
251266
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-
287267 fn visit_var_debug_info ( & mut self , var_debug_info : & mir:: VarDebugInfo < ' tcx > ) {
288268 // Indirect debuginfo requires going through memory, that only
289269 // the debugger accesses, following our emitted DWARF pointer ops.
0 commit comments