@@ -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,55 @@ 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
- }
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 ;
137
142
}
138
- }
139
143
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" ) ,
143
145
}
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) ;
158
146
}
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) ;
159
151
}
160
152
}
161
153
0 commit comments