@@ -319,16 +319,40 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
319319 OperandRef { val, layout }
320320 }
321321
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).
322331 pub ( crate ) fn extract_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
323332 & self ,
324333 fx : & mut FunctionCx < ' a , ' tcx , Bx > ,
325334 bx : & mut Bx ,
326- i : usize ,
335+ downcast_variant : Option < VariantIdx > ,
336+ field_idx : FieldIdx ,
327337 ) -> 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+ } ;
330351
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) {
332356 // Part of https://github.com/rust-lang/compiler-team/issues/838
333357 span_bug ! (
334358 fx. mir. span,
@@ -338,18 +362,22 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
338362
339363 let val = if field. is_zst ( ) {
340364 OperandValue :: ZeroSized
341- } else if let BackendRepr :: SimdVector { .. } = self . layout . backend_repr {
365+ } else if let BackendRepr :: SimdVector { .. } = layout. backend_repr {
342366 // codegen_transmute_operand doesn't support SIMD, but since the previous
343367 // check handled ZSTs, the only possible field access into something SIMD
344368 // is to the `non_1zst_field` that's the same SIMD. (Other things, even
345369 // just padding, would change the wrapper's representation type.)
346- assert_eq ! ( field. size, self . layout. size) ;
370+ assert_eq ! ( field. size, layout. size) ;
347371 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+ }
351379 } else {
352- let ( in_scalar, imm) = match ( self . val , self . layout . backend_repr ) {
380+ let ( in_scalar, imm) = match ( self . val , layout. backend_repr ) {
353381 // Extract a scalar component from a pair.
354382 ( OperandValue :: Pair ( a_llval, b_llval) , BackendRepr :: ScalarPair ( a, b) ) => {
355383 // This needs to look at `offset`, rather than `i`, because
@@ -371,19 +399,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
371399 }
372400 } ;
373401 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 ( ) => {
376403 // For a type like `Result<usize, &u32>` the layout is `Pair(i64, ptr)`.
377404 // But if we're reading the `Ok` payload, we need to turn that `ptr`
378405 // back into an integer. To avoid repeating logic we do that by
379406 // calling the transmute code, which is legal thanks to the size
380407 // assert we did when pulling it out of the pair.
381408 transmute_scalar ( bx, imm, in_scalar, out_scalar)
382409 }
410+ BackendRepr :: Scalar ( _) | BackendRepr :: SimdVector { .. } => imm,
383411 BackendRepr :: ScalarPair ( _, _) | BackendRepr :: Memory { .. } => bug ! ( ) ,
384412 } )
385413 } ;
386-
387414 OperandRef { val, layout : field }
388415 }
389416
@@ -431,7 +458,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
431458 let tag_op = match self . val {
432459 OperandValue :: ZeroSized => bug ! ( ) ,
433460 OperandValue :: Immediate ( _) | OperandValue :: Pair ( _, _) => {
434- self . extract_field ( fx, bx, tag_field. as_usize ( ) )
461+ self . extract_field ( fx, bx, None , tag_field)
435462 }
436463 OperandValue :: Ref ( place) => {
437464 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> {
922949 ) -> Option < OperandRef < ' tcx , Bx :: Value > > {
923950 debug ! ( "maybe_codegen_consume_direct(place_ref={:?})" , place_ref) ;
924951
952+ let mut downcast_variant = None ;
925953 match self . locals [ place_ref. local ] {
926954 LocalRef :: Operand ( mut o) => {
927955 // 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> {
933961 "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
934962 but tried to access field {f:?} of pointer {o:?}",
935963 ) ;
936- o = o. extract_field ( self , bx, f. index ( ) ) ;
964+ o = o. extract_field ( self , bx, downcast_variant, f) ;
965+ downcast_variant = None ;
937966 }
938967 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) ;
953969 }
954970 _ => return None ,
955971 }
956972 }
973+ debug_assert_eq ! ( downcast_variant, None ) ;
957974
958975 Some ( o)
959976 }
0 commit comments