@@ -5,8 +5,8 @@ use rustc_data_structures::graph::dominators::Dominators;
5
5
use rustc_index:: bit_set:: DenseBitSet ;
6
6
use rustc_index:: { IndexSlice , IndexVec } ;
7
7
use 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 ;
10
10
use rustc_middle:: { bug, span_bug} ;
11
11
use tracing:: debug;
12
12
@@ -96,65 +96,92 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
96
96
fn process_place (
97
97
& mut self ,
98
98
place_ref : & mir:: PlaceRef < ' tcx > ,
99
- context : PlaceContext ,
99
+ mut context : PlaceContext ,
100
100
location : Location ,
101
101
) {
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,
117
109
) ;
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
+ } ;
144
114
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 {
150
120
self . visit_local (
151
- local ,
121
+ index_local ,
152
122
PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ,
153
123
location,
154
124
) ;
155
125
}
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) ;
158
185
}
159
186
}
160
187
}
0 commit comments