@@ -4,6 +4,7 @@ use crate::simplify::simplify_duplicate_switch_targets;
4
4
use crate :: take_array;
5
5
use rustc_ast:: attr;
6
6
use rustc_hir:: LangItem ;
7
+ use rustc_index:: IndexVec ;
7
8
use rustc_middle:: bug;
8
9
use rustc_middle:: mir:: * ;
9
10
use rustc_middle:: ty:: layout;
@@ -60,8 +61,8 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
60
61
_ => { }
61
62
}
62
63
}
63
-
64
64
ctx. simplify_primitive_clone ( block. terminator . as_mut ( ) . unwrap ( ) , & mut block. statements ) ;
65
+ ctx. simplify_copy_like ( & mut block. statements ) ;
65
66
ctx. simplify_intrinsic_assert ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
66
67
ctx. simplify_nounwind_call ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
67
68
simplify_duplicate_switch_targets ( block. terminator . as_mut ( ) . unwrap ( ) ) ;
@@ -207,6 +208,83 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
207
208
}
208
209
}
209
210
211
+ /// Transform `Aggregate(Adt, [(*_1).0, (*_1).1])` ==> `Copy(*_1)`.
212
+ /// This comes from the simplification of the clone method by `simplify_primitive_clone`.
213
+ fn simplify_copy_like ( & self , statements : & mut Vec < Statement < ' tcx > > ) {
214
+ let mut assignments = IndexVec :: from_elem ( None :: < Place < ' tcx > > , self . local_decls ) ;
215
+ for statement in statements {
216
+ match statement. kind {
217
+ StatementKind :: Assign ( box ( dest, ref mut rvalue) ) => {
218
+ if let Rvalue :: Aggregate ( _, fields) = rvalue {
219
+ let mut from_local = None ;
220
+ if fields. iter_enumerated ( ) . all ( |( index, field) | {
221
+ let Some ( from_place) = field
222
+ . place ( )
223
+ . and_then ( |p| p. as_local ( ) )
224
+ . and_then ( |l| assignments[ l] )
225
+ else {
226
+ return false ;
227
+ } ;
228
+ // All fields must come from the same local.
229
+ if let Some ( from_local) = from_local {
230
+ if from_place. local != from_local {
231
+ return false ;
232
+ }
233
+ } else {
234
+ // We can only copy the same type.
235
+ let Some ( from_ty) =
236
+ self . local_decls [ from_place. local ] . ty . builtin_deref ( false )
237
+ else {
238
+ return false ;
239
+ } ;
240
+ let dest_ty = dest. ty ( self . local_decls , self . tcx ) . ty ;
241
+ if dest_ty != from_ty {
242
+ return false ;
243
+ } ;
244
+ from_local = Some ( from_place. local ) ;
245
+ }
246
+ // For more complex scenarios, we expect to get this simplified projection within a complete pipeline.
247
+ let [ ProjectionElem :: Deref , ProjectionElem :: Field ( from_index, _) ] =
248
+ * from_place. projection . as_slice ( )
249
+ else {
250
+ return false ;
251
+ } ;
252
+ from_index == index
253
+ } ) {
254
+ if let Some ( local) = from_local {
255
+ if self . should_simplify ( & statement. source_info , rvalue) {
256
+ * rvalue = Rvalue :: Use ( Operand :: Copy ( Place {
257
+ local,
258
+ projection : self
259
+ . tcx
260
+ . mk_place_elems ( & [ ProjectionElem :: Deref ] ) ,
261
+ } ) ) ;
262
+ }
263
+ }
264
+ }
265
+ }
266
+ // Collect available assignments, including those transformed from `Aggregate`.
267
+ if let Some ( local) = dest. as_local ( ) {
268
+ assignments[ local] = if let Rvalue :: Use ( Operand :: Copy ( place) ) = rvalue {
269
+ Some ( * place)
270
+ } else {
271
+ // This assignment generally comes from debuginfo (e.g., Ref),
272
+ // but we still need to check if a local is being overridden.
273
+ None
274
+ } ;
275
+ } else {
276
+ // We don't handle projection, so we drop all previous assignments.
277
+ assignments. reset_all ( None ) ;
278
+ }
279
+ }
280
+ StatementKind :: StorageLive ( _) | StatementKind :: StorageDead ( _) => { }
281
+ _ => {
282
+ assignments. reset_all ( None ) ;
283
+ }
284
+ }
285
+ }
286
+ }
287
+
210
288
fn simplify_cast ( & self , rvalue : & mut Rvalue < ' tcx > ) {
211
289
if let Rvalue :: Cast ( kind, operand, cast_ty) = rvalue {
212
290
let operand_ty = operand. ty ( self . local_decls , self . tcx ) ;
0 commit comments