@@ -319,16 +319,40 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
319
319
OperandRef { val, layout }
320
320
}
321
321
322
+ /// Extracts field `field_idx` from `self`, after downcasting to
323
+ /// `downcast_variant` if it's specified.
324
+ ///
325
+ /// Reading from things like tuples or structs, which are always single-variant,
326
+ /// don't need to pass a downcast variant since downcasting them to
327
+ /// `FIRST_VARIANT` doesn't actually change anything.
328
+ /// Things like enums and coroutines, though, must pass the variant from which
329
+ /// they want to read unless they're specifically reading the tag field
330
+ /// (which is the index at the type level, not inside one of the variants).
322
331
pub ( crate ) fn extract_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
323
332
& self ,
324
333
fx : & mut FunctionCx < ' a , ' tcx , Bx > ,
325
334
bx : & mut Bx ,
326
- i : usize ,
335
+ downcast_variant : Option < VariantIdx > ,
336
+ field_idx : FieldIdx ,
327
337
) -> Self {
328
- let field = self . layout . field ( bx. cx ( ) , i) ;
329
- let offset = self . layout . fields . offset ( i) ;
338
+ let layout = if let Some ( vidx) = downcast_variant {
339
+ self . layout . for_variant ( bx. cx ( ) , vidx)
340
+ } else {
341
+ debug_assert ! (
342
+ match self . layout. variants {
343
+ Variants :: Empty => true ,
344
+ Variants :: Single { index } => index == FIRST_VARIANT ,
345
+ Variants :: Multiple { tag_field, .. } => tag_field == field_idx,
346
+ } ,
347
+ "Should have specified a variant to read field {field_idx:?} of {self:?}" ,
348
+ ) ;
349
+ self . layout
350
+ } ;
330
351
331
- if !bx. is_backend_ref ( self . layout ) && bx. is_backend_ref ( field) {
352
+ let field = layout. field ( bx. cx ( ) , field_idx. as_usize ( ) ) ;
353
+ let offset = layout. fields . offset ( field_idx. as_usize ( ) ) ;
354
+
355
+ if !bx. is_backend_ref ( layout) && bx. is_backend_ref ( field) {
332
356
// Part of https://github.com/rust-lang/compiler-team/issues/838
333
357
span_bug ! (
334
358
fx. mir. span,
@@ -338,18 +362,22 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
338
362
339
363
let val = if field. is_zst ( ) {
340
364
OperandValue :: ZeroSized
341
- } else if let BackendRepr :: SimdVector { .. } = self . layout . backend_repr {
365
+ } else if let BackendRepr :: SimdVector { .. } = layout. backend_repr {
342
366
// codegen_transmute_operand doesn't support SIMD, but since the previous
343
367
// check handled ZSTs, the only possible field access into something SIMD
344
368
// is to the `non_1zst_field` that's the same SIMD. (Other things, even
345
369
// just padding, would change the wrapper's representation type.)
346
- assert_eq ! ( field. size, self . layout. size) ;
370
+ assert_eq ! ( field. size, layout. size) ;
347
371
self . val
348
- } else if field. size == self . layout . size {
349
- assert_eq ! ( offset. bytes( ) , 0 ) ;
350
- fx. codegen_transmute_operand ( bx, * self , field)
372
+ } else if field. size == layout. size {
373
+ debug_assert_eq ! ( offset. bytes( ) , 0 ) ;
374
+ if downcast_variant. is_some ( ) {
375
+ fx. codegen_transmute_operand ( bx, * self , field)
376
+ } else {
377
+ self . val
378
+ }
351
379
} else {
352
- let ( in_scalar, imm) = match ( self . val , self . layout . backend_repr ) {
380
+ let ( in_scalar, imm) = match ( self . val , layout. backend_repr ) {
353
381
// Extract a scalar component from a pair.
354
382
( OperandValue :: Pair ( a_llval, b_llval) , BackendRepr :: ScalarPair ( a, b) ) => {
355
383
// This needs to look at `offset`, rather than `i`, because
@@ -371,19 +399,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
371
399
}
372
400
} ;
373
401
OperandValue :: Immediate ( match field. backend_repr {
374
- BackendRepr :: SimdVector { .. } => imm,
375
- BackendRepr :: Scalar ( out_scalar) => {
402
+ BackendRepr :: Scalar ( out_scalar) if downcast_variant. is_some ( ) => {
376
403
// For a type like `Result<usize, &u32>` the layout is `Pair(i64, ptr)`.
377
404
// But if we're reading the `Ok` payload, we need to turn that `ptr`
378
405
// back into an integer. To avoid repeating logic we do that by
379
406
// calling the transmute code, which is legal thanks to the size
380
407
// assert we did when pulling it out of the pair.
381
408
transmute_scalar ( bx, imm, in_scalar, out_scalar)
382
409
}
410
+ BackendRepr :: Scalar ( _) | BackendRepr :: SimdVector { .. } => imm,
383
411
BackendRepr :: ScalarPair ( _, _) | BackendRepr :: Memory { .. } => bug ! ( ) ,
384
412
} )
385
413
} ;
386
-
387
414
OperandRef { val, layout : field }
388
415
}
389
416
@@ -431,7 +458,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
431
458
let tag_op = match self . val {
432
459
OperandValue :: ZeroSized => bug ! ( ) ,
433
460
OperandValue :: Immediate ( _) | OperandValue :: Pair ( _, _) => {
434
- self . extract_field ( fx, bx, tag_field. as_usize ( ) )
461
+ self . extract_field ( fx, bx, None , tag_field)
435
462
}
436
463
OperandValue :: Ref ( place) => {
437
464
let tag = place. with_type ( self . layout ) . project_field ( bx, tag_field. as_usize ( ) ) ;
@@ -922,6 +949,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
922
949
) -> Option < OperandRef < ' tcx , Bx :: Value > > {
923
950
debug ! ( "maybe_codegen_consume_direct(place_ref={:?})" , place_ref) ;
924
951
952
+ let mut downcast_variant = None ;
925
953
match self . locals [ place_ref. local ] {
926
954
LocalRef :: Operand ( mut o) => {
927
955
// Moves out of scalar and scalar pair fields are trivial.
@@ -933,27 +961,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
933
961
"Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
934
962
but tried to access field {f:?} of pointer {o:?}",
935
963
) ;
936
- o = o. extract_field ( self , bx, f. index ( ) ) ;
964
+ o = o. extract_field ( self , bx, downcast_variant, f) ;
965
+ downcast_variant = None ;
937
966
}
938
967
mir:: ProjectionElem :: Downcast ( _sym, variant_idx) => {
939
- let layout = o. layout . for_variant ( bx. cx ( ) , variant_idx) ;
940
- let val = match layout. backend_repr {
941
- // The transmute here handles cases like `Result<bool, u8>`
942
- // where the immediate values need to change for
943
- // the specific types in the cast-to variant.
944
- BackendRepr :: Scalar ( ..) | BackendRepr :: ScalarPair ( ..) => {
945
- self . codegen_transmute_operand ( bx, o, layout)
946
- }
947
- BackendRepr :: SimdVector { .. } | BackendRepr :: Memory { .. } => {
948
- o. val
949
- }
950
- } ;
951
-
952
- o = OperandRef { val, layout } ;
968
+ downcast_variant = Some ( variant_idx) ;
953
969
}
954
970
_ => return None ,
955
971
}
956
972
}
973
+ debug_assert_eq ! ( downcast_variant, None ) ;
957
974
958
975
Some ( o)
959
976
}
0 commit comments