@@ -53,7 +53,7 @@ impl SsaLocals {
5353 body : & Body < ' tcx > ,
5454 borrowed_locals : & BitSet < Local > ,
5555 ) -> SsaLocals {
56- let assignment_order = Vec :: new ( ) ;
56+ let assignment_order = Vec :: with_capacity ( body . local_decls . len ( ) ) ;
5757
5858 let assignments = IndexVec :: from_elem ( Set1 :: Empty , & body. local_decls ) ;
5959 let dominators =
@@ -179,37 +179,61 @@ struct SsaVisitor {
179179 assignment_order : Vec < Local > ,
180180}
181181
182+ impl SsaVisitor {
183+ fn check_assignment_dominates ( & mut self , local : Local , loc : Location ) {
184+ let set = & mut self . assignments [ local] ;
185+ let assign_dominates = match * set {
186+ Set1 :: Empty | Set1 :: Many => false ,
187+ Set1 :: One ( LocationExtended :: Arg ) => true ,
188+ Set1 :: One ( LocationExtended :: Plain ( assign) ) => {
189+ assign. successor_within_block ( ) . dominates ( loc, & self . dominators )
190+ }
191+ } ;
192+ // We are visiting a use that is not dominated by an assignment.
193+ // Either there is a cycle involved, or we are reading for uninitialized local.
194+ // Bail out.
195+ if !assign_dominates {
196+ * set = Set1 :: Many ;
197+ }
198+ }
199+ }
200+
182201impl < ' tcx > Visitor < ' tcx > for SsaVisitor {
183202 fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , loc : Location ) {
184203 match ctxt {
185204 PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) => {
186205 self . assignments [ local] . insert ( LocationExtended :: Plain ( loc) ) ;
187- self . assignment_order . push ( local) ;
206+ if let Set1 :: One ( _) = self . assignments [ local] {
207+ // Only record if SSA-like, to avoid growing the vector needlessly.
208+ self . assignment_order . push ( local) ;
209+ }
188210 }
189211 // Anything can happen with raw pointers, so remove them.
190212 PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: AddressOf )
191213 | PlaceContext :: MutatingUse ( _) => self . assignments [ local] = Set1 :: Many ,
192214 // Immutable borrows are taken into account in `SsaLocals::new` by
193215 // removing non-freeze locals.
194216 PlaceContext :: NonMutatingUse ( _) => {
195- let set = & mut self . assignments [ local] ;
196- let assign_dominates = match * set {
197- Set1 :: Empty | Set1 :: Many => false ,
198- Set1 :: One ( LocationExtended :: Arg ) => true ,
199- Set1 :: One ( LocationExtended :: Plain ( assign) ) => {
200- assign. successor_within_block ( ) . dominates ( loc, & self . dominators )
201- }
202- } ;
203- // We are visiting a use that is not dominated by an assignment.
204- // Either there is a cycle involved, or we are reading for uninitialized local.
205- // Bail out.
206- if !assign_dominates {
207- * set = Set1 :: Many ;
208- }
217+ self . check_assignment_dominates ( local, loc) ;
209218 }
210219 PlaceContext :: NonUse ( _) => { }
211220 }
212221 }
222+
223+ fn visit_place ( & mut self , place : & Place < ' tcx > , ctxt : PlaceContext , loc : Location ) {
224+ if place. projection . first ( ) == Some ( & PlaceElem :: Deref ) {
225+ // Do not do anything for storage statements and debuginfo.
226+ if ctxt. is_use ( ) {
227+ // A use through a `deref` only reads from the local, and cannot write to it.
228+ let new_ctxt = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Projection ) ;
229+
230+ self . visit_projection ( place. as_ref ( ) , new_ctxt, loc) ;
231+ self . check_assignment_dominates ( place. local , loc) ;
232+ }
233+ return ;
234+ }
235+ self . super_place ( place, ctxt, loc) ;
236+ }
213237}
214238
215239#[ instrument( level = "trace" , skip( ssa, body) ) ]
0 commit comments