@@ -6,7 +6,7 @@ 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
8
use rustc_middle:: mir:: { self , DefLocation , Location , TerminatorKind , traversal} ;
9
- use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf } ;
9
+ use rustc_middle:: ty:: layout:: LayoutOf ;
10
10
use rustc_middle:: { bug, span_bug} ;
11
11
use tracing:: debug;
12
12
@@ -99,63 +99,64 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
99
99
context : PlaceContext ,
100
100
location : Location ,
101
101
) {
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
+ }
103
112
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
+ }
110
118
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
+ }
128
127
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
- }
128
+ if !place_ref. projection . is_empty ( ) && context. is_mutating_use ( ) {
129
+ // If it's a mutating use it doesn't matter what the projections are,
130
+ // if there are *any* then we need a place to write. (For example,
131
+ // `_1 = Foo()` works in SSA but `_2.0 = Foo()` does not.)
132
+ let mut_projection = PlaceContext :: MutatingUse ( MutatingUseContext :: Projection ) ;
133
+ self . visit_local ( place_ref. local , mut_projection, location) ;
134
+ return ;
135
+ }
139
136
140
- if let mir:: ProjectionElem :: Deref = elem {
141
- // Deref projections typically only read the pointer.
142
- base_context = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ;
143
- }
137
+ for elem in place_ref. projection {
138
+ // Scan through to ensure the only projections are those which
139
+ // `FunctionCx::maybe_codegen_consume_direct` can handle.
140
+ match elem {
141
+ mir:: PlaceElem :: Field ( ..) | mir:: PlaceElem :: Downcast ( ..) => { }
142
+
143
+ mir:: PlaceElem :: Index ( ..)
144
+ | mir:: PlaceElem :: ConstantIndex { .. }
145
+ | mir:: PlaceElem :: Subslice { .. }
146
+ | mir:: PlaceElem :: OpaqueCast ( ..)
147
+ | mir:: PlaceElem :: UnwrapUnsafeBinder ( ..)
148
+ | mir:: PlaceElem :: Subtype ( ..) => {
149
+ self . locals [ place_ref. local ] = LocalKind :: Memory ;
150
+ return ;
151
+ }
144
152
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
- ) ;
153
+ mir:: PlaceElem :: Deref => bug ! ( "Deref after first position" ) ,
155
154
}
156
- } else {
157
- self . visit_local ( place_ref. local , context, location) ;
158
155
}
156
+
157
+ // Even with supported projections, we still need to have `visit_local`
158
+ // check for things that can't be done in SSA (like `SharedBorrow`).
159
+ self . visit_local ( place_ref. local , context, location) ;
159
160
}
160
161
}
161
162
@@ -171,8 +172,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer
171
172
if let Some ( local) = place. as_local ( ) {
172
173
self . define ( local, DefLocation :: Assignment ( location) ) ;
173
174
if self . locals [ local] != LocalKind :: Memory {
174
- let decl_span = self . fx . mir . local_decls [ local] . source_info . span ;
175
- if !self . fx . rvalue_creates_operand ( rvalue, decl_span) {
175
+ if !self . fx . rvalue_creates_operand ( rvalue) {
176
176
self . locals [ local] = LocalKind :: Memory ;
177
177
}
178
178
}
0 commit comments