@@ -6,7 +6,7 @@ use rustc_index::bit_set::DenseBitSet;
66use rustc_index:: { IndexSlice , IndexVec } ;
77use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
88use rustc_middle:: mir:: { self , DefLocation , Location , TerminatorKind , traversal} ;
9- use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf } ;
9+ use rustc_middle:: ty:: layout:: LayoutOf ;
1010use rustc_middle:: { bug, span_bug} ;
1111use tracing:: debug;
1212
@@ -99,63 +99,55 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
9999 context : PlaceContext ,
100100 location : Location ,
101101 ) {
102- let cx = self . fx . cx ;
102+ const COPY_CONTEXT : PlaceContext =
103+ PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ;
104+
105+ // `PlaceElem::Index` is the only variant that can mention other `Local`s,
106+ // so check for those up-front before any potential short-circuits.
107+ for elem in place_ref. projection {
108+ if let mir:: PlaceElem :: Index ( index_local) = * elem {
109+ self . visit_local ( index_local, COPY_CONTEXT , location) ;
110+ }
111+ }
103112
104- if let Some ( ( place_base, elem) ) = place_ref. last_projection ( ) {
105- let mut base_context = if context. is_mutating_use ( ) {
106- PlaceContext :: MutatingUse ( MutatingUseContext :: Projection )
107- } else {
108- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Projection )
109- } ;
113+ // If our local is already memory, nothing can make it *more* memory
114+ // so we don't need to bother checking the projections further.
115+ if self . locals [ place_ref. local ] == LocalKind :: Memory {
116+ return ;
117+ }
110118
111- // Allow uses of projections that are ZSTs or from scalar fields.
112- let is_consume = matches ! (
113- context,
114- PlaceContext :: NonMutatingUse (
115- NonMutatingUseContext :: Copy | NonMutatingUseContext :: Move ,
116- )
117- ) ;
118- if is_consume {
119- let base_ty = place_base. ty ( self . fx . mir , cx. tcx ( ) ) ;
120- let base_ty = self . fx . monomorphize ( base_ty) ;
121-
122- // ZSTs don't require any actual memory access.
123- let elem_ty = base_ty. projection_ty ( cx. tcx ( ) , self . fx . monomorphize ( elem) ) . ty ;
124- let span = self . fx . mir . local_decls [ place_ref. local ] . source_info . span ;
125- if cx. spanned_layout_of ( elem_ty, span) . is_zst ( ) {
126- return ;
127- }
119+ if place_ref. is_indirect_first_projection ( ) {
120+ // If this starts with a `Deref`, we only need to record a read of the
121+ // pointer being dereferenced, as all the subsequent projections are
122+ // working on a place which is always supported. (And because we're
123+ // looking at codegen MIR, it can only happen as the first projection.)
124+ self . visit_local ( place_ref. local , COPY_CONTEXT , location) ;
125+ return ;
126+ }
128127
129- if let mir:: ProjectionElem :: Field ( ..) = elem {
130- let layout = cx. spanned_layout_of ( base_ty. ty , span) ;
131- if cx. is_backend_immediate ( layout) || cx. is_backend_scalar_pair ( layout) {
132- // Recurse with the same context, instead of `Projection`,
133- // potentially stopping at non-operand projections,
134- // which would trigger `not_ssa` on locals.
135- base_context = context;
136- }
128+ for elem in place_ref. projection {
129+ // Scan through to ensure the only projections are those which
130+ // `FunctionCx::maybe_codegen_consume_direct` can handle.
131+ match elem {
132+ mir:: PlaceElem :: Field ( ..) | mir:: PlaceElem :: Downcast ( ..) => { }
133+
134+ mir:: PlaceElem :: Index ( ..)
135+ | mir:: PlaceElem :: ConstantIndex { .. }
136+ | mir:: PlaceElem :: Subslice { .. }
137+ | mir:: PlaceElem :: OpaqueCast ( ..)
138+ | mir:: PlaceElem :: UnwrapUnsafeBinder ( ..)
139+ | mir:: PlaceElem :: Subtype ( ..) => {
140+ self . locals [ place_ref. local ] = LocalKind :: Memory ;
141+ return ;
137142 }
138- }
139143
140- if let mir:: ProjectionElem :: Deref = elem {
141- // Deref projections typically only read the pointer.
142- base_context = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ;
144+ mir:: PlaceElem :: Deref => bug ! ( "Deref after first position" ) ,
143145 }
144-
145- self . process_place ( & place_base, base_context, location) ;
146- // HACK(eddyb) this emulates the old `visit_projection_elem`, this
147- // entire `visit_place`-like `process_place` method should be rewritten,
148- // now that we have moved to the "slice of projections" representation.
149- if let mir:: ProjectionElem :: Index ( local) = elem {
150- self . visit_local (
151- local,
152- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ,
153- location,
154- ) ;
155- }
156- } else {
157- self . visit_local ( place_ref. local , context, location) ;
158146 }
147+
148+ // Even with supported projections, we still need to have `visit_local`
149+ // check for things that can't be done in SSA (like `SharedBorrow`).
150+ self . visit_local ( place_ref. local , context, location) ;
159151 }
160152}
161153
0 commit comments