@@ -5,8 +5,8 @@ use rustc_data_structures::graph::dominators::Dominators;
55use rustc_index:: bit_set:: DenseBitSet ;
66use rustc_index:: { IndexSlice , IndexVec } ;
77use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
8- use rustc_middle:: mir:: { self , DefLocation , Location , TerminatorKind , traversal} ;
9- use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf } ;
8+ use rustc_middle:: mir:: { self , DefLocation , Location , PlaceElem , TerminatorKind , traversal} ;
9+ use rustc_middle:: ty:: layout:: LayoutOf ;
1010use rustc_middle:: { bug, span_bug} ;
1111use tracing:: debug;
1212
@@ -96,65 +96,92 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
9696 fn process_place (
9797 & mut self ,
9898 place_ref : & mir:: PlaceRef < ' tcx > ,
99- context : PlaceContext ,
99+ mut context : PlaceContext ,
100100 location : Location ,
101101 ) {
102- let cx = self . fx . cx ;
103-
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- } ;
110-
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- )
102+ let maybe_local = if place_ref. is_indirect_first_projection ( ) {
103+ // After we deref a pointer, the local *of that pointer* is no
104+ // longer interesting for the rest of the projection chain.
105+ self . visit_local (
106+ place_ref. local ,
107+ PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ,
108+ location,
117109 ) ;
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- }
128-
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- }
137- }
138- }
139-
140- if let mir:: ProjectionElem :: Deref = elem {
141- // Deref projections typically only read the pointer.
142- base_context = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ;
143- }
110+ None
111+ } else {
112+ Some ( place_ref. local )
113+ } ;
144114
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 {
115+ let mut projection : & [ PlaceElem < ' tcx > ] = place_ref . projection ;
116+ loop {
117+ // Index projections are the only ones with another local, so handle
118+ // that special case before the normal projection match .
119+ if let [ PlaceElem :: Index ( index_local ) , .. ] = * projection {
150120 self . visit_local (
151- local ,
121+ index_local ,
152122 PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ,
153123 location,
154124 ) ;
155125 }
156- } else {
157- self . visit_local ( place_ref. local , context, location) ;
126+
127+ projection = match projection {
128+ // No more projections means we're done looping.
129+ [ ] => break ,
130+ // The only deref allowed in a Runtime-phase place is at the
131+ // beginning, which we checked before the loop.
132+ [ PlaceElem :: Deref , rest @ ..] => {
133+ assert_eq ! ( maybe_local, None ) ;
134+ rest
135+ }
136+ // Making SSA locals useful for non-primitives heavily depends on
137+ // not forcing stack allocation for basic newtypes and simple
138+ // enums like `Option<u32>` or `Result<bool, Box<MyError>>`.
139+ [ PlaceElem :: Downcast { .. } , PlaceElem :: Field { .. } , rest @ ..]
140+ | [ PlaceElem :: Field { .. } , rest @ ..] => {
141+ if let PlaceContext :: NonMutatingUse (
142+ NonMutatingUseContext :: Copy
143+ | NonMutatingUseContext :: Move
144+ | NonMutatingUseContext :: Inspect ,
145+ ) = context
146+ {
147+ // Reading fields (or pseudo-fields) in operands can stay SSA
148+ } else {
149+ // But storing into a projection needs memory, especially for function returns
150+ context = PlaceContext :: MutatingUse ( MutatingUseContext :: Projection ) ;
151+ }
152+ rest
153+ }
154+ [ PlaceElem :: Downcast { .. } , ..] => {
155+ span_bug ! ( self . fx. mir. span, "Non-field downcast in {place_ref:?}" ) ;
156+ }
157+ // FIXME: These are type-changing, but not layout-affecting, so
158+ // they probably needn't force memory, but for now they do since
159+ // `maybe_codegen_consume_direct` doesn't handle them.
160+ [
161+ PlaceElem :: OpaqueCast { .. }
162+ | PlaceElem :: UnwrapUnsafeBinder { .. }
163+ | PlaceElem :: Subtype { .. } ,
164+ rest @ ..,
165+ ] => {
166+ context = PlaceContext :: MutatingUse ( MutatingUseContext :: Projection ) ;
167+ rest
168+ }
169+ // The various types of indexing use address arithmetic, so we
170+ // need to force the local to Memory like a borrow would.
171+ [
172+ PlaceElem :: Index { .. }
173+ | PlaceElem :: ConstantIndex { .. }
174+ | PlaceElem :: Subslice { .. } ,
175+ rest @ ..,
176+ ] => {
177+ context = PlaceContext :: MutatingUse ( MutatingUseContext :: Projection ) ;
178+ rest
179+ }
180+ } ;
181+ }
182+
183+ if let Some ( local) = maybe_local {
184+ self . visit_local ( local, context, location) ;
158185 }
159186 }
160187}
0 commit comments