@@ -580,7 +580,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
580580 ) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , VariantIdx ) > {
581581 trace ! ( "read_discriminant_value {:#?}" , rval. layout) ;
582582
583- let ( discr_scalar_layout, discr_kind, discr_index) = match rval. layout . variants {
583+ // We use "discriminant" to refer to the value associated with a particualr enum variant.
584+ // This is not to be confused with its "variant index", which is just determining its position in the
585+ // declared list of variants -- they can differ with explicitly assigned discriminants.
586+ // We use "tag" to refer to how the discriminant is encoded in memory, which can be either
587+ // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`).
588+ // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things
589+ // rather confusing.
590+ let ( tag_scalar_layout, tag_kind, tag_index) = match rval. layout . variants {
584591 Variants :: Single { index } => {
585592 let discr = match rval. layout . ty . discriminant_for_variant ( * self . tcx , index) {
586593 Some ( discr) => {
@@ -602,31 +609,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
602609 } ;
603610
604611 // There are *three* types/layouts that come into play here:
605- // - The field storing the discriminant has a layout, which my be a pointer.
606- // This is `discr_val.layout`; we just use it for sanity checks .
607- // - The discriminant has a layout for tag storing purposes, which is always an integer .
608- // This is `discr_layout` and is used to interpret the value we read from the
609- // discriminant field.
610- // - The discriminant also has a type for typechecking, and that type's
611- // layout can be *different* . This is `discr_ty`, and is used for the `Scalar`
612- // we return. If necessary, a cast from `discr_layout` is performed .
612+ // - The discriminant has a type for typechecking. This is `discr_ty`, and is used for
613+ // the `Scalar` we return .
614+ // - The discriminant gets encoded as a tag/niche, with layout `tag_layout` .
615+ // This is always an integer, and used to interpret the value we read from the
616+ // tag field. For the return value, a cast to `discr_ty` is performed .
617+ // - The field storing the tag has a layout, which is very similar to
618+ // `tag_layout` but may be a pointer . This is `tag_val.layout`;
619+ // we just use it for sanity checks .
613620
614621 // Get layout for tag.
615- let discr_layout = self . layout_of ( discr_scalar_layout . value . to_int_ty ( * self . tcx ) ) ?;
622+ let tag_layout = self . layout_of ( tag_scalar_layout . value . to_int_ty ( * self . tcx ) ) ?;
616623
617- // Read discriminant value and sanity-check `discr_layout `.
618- let discr_val = self . read_immediate ( self . operand_field ( rval, discr_index ) ?) ?;
619- assert_eq ! ( discr_layout . size, discr_val . layout. size) ;
620- assert_eq ! ( discr_layout . abi. is_signed( ) , discr_val . layout. abi. is_signed( ) ) ;
621- let discr_val = discr_val . to_scalar ( ) ?;
622- trace ! ( "discriminant value: {:?}" , discr_val ) ;
624+ // Read tag and sanity-check `tag_layout `.
625+ let tag_val = self . read_immediate ( self . operand_field ( rval, tag_index ) ?) ?;
626+ assert_eq ! ( tag_layout . size, tag_val . layout. size) ;
627+ assert_eq ! ( tag_layout . abi. is_signed( ) , tag_val . layout. abi. is_signed( ) ) ;
628+ let tag_val = tag_val . to_scalar ( ) ?;
629+ trace ! ( "tag value: {:?}" , tag_val ) ;
623630
624631 // Get type used by typechecking.
625632 let discr_ty = match rval. layout . ty . kind {
626633 ty:: Adt ( adt, _) => {
627634 let discr_int_ty = Integer :: from_attr ( self , adt. repr . discr_type ( ) ) ;
628635 // The signedness of tag and discriminant is the same.
629- discr_int_ty. to_ty ( * self . tcx , discr_layout . abi . is_signed ( ) )
636+ discr_int_ty. to_ty ( * self . tcx , tag_layout . abi . is_signed ( ) )
630637 }
631638 ty:: Generator ( _, substs, _) => {
632639 let substs = substs. as_generator ( ) ;
@@ -636,17 +643,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
636643 } ;
637644
638645 // Figure out which discriminant and variant this corresponds to.
639- Ok ( match * discr_kind {
646+ Ok ( match * tag_kind {
640647 DiscriminantKind :: Tag => {
641- let discr_bits = self
642- . force_bits ( discr_val , discr_layout . size )
643- . map_err ( |_| err_ub ! ( InvalidDiscriminant ( discr_val . erase_tag( ) ) ) ) ?;
644- // Cast discriminant bits to the right type .
645- let discr_ty_layout = self . layout_of ( discr_ty) ?;
648+ let tag_bits = self
649+ . force_bits ( tag_val , tag_layout . size )
650+ . map_err ( |_| err_ub ! ( InvalidDiscriminant ( tag_val . erase_tag( ) ) ) ) ?;
651+ // Cast bits from tag layout to discriminant layout .
652+ let discr_layout = self . layout_of ( discr_ty) ?;
646653 let discr_val_cast =
647- self . cast_from_scalar ( discr_bits , discr_layout , discr_ty) ;
648- let discr_bits = discr_val_cast. assert_bits ( discr_ty_layout . size ) ;
649- // Find variant index for this tag , and catch invalid discriminants.
654+ self . cast_from_scalar ( tag_bits , tag_layout , discr_ty) ;
655+ let discr_bits = discr_val_cast. assert_bits ( discr_layout . size ) ;
656+ // Convert discriminant to variant index , and catch invalid discriminants.
650657 let index = match rval. layout . ty . kind {
651658 ty:: Adt ( adt, _) => {
652659 adt. discriminants ( self . tcx . tcx ) . find ( |( _, var) | var. val == discr_bits)
@@ -659,36 +666,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
659666 }
660667 _ => bug ! ( "tagged layout for non-adt non-generator" ) ,
661668 }
662- . ok_or_else ( || err_ub ! ( InvalidDiscriminant ( discr_val . erase_tag( ) ) ) ) ?;
669+ . ok_or_else ( || err_ub ! ( InvalidDiscriminant ( tag_val . erase_tag( ) ) ) ) ?;
663670 // Return the cast value, and the index.
664671 ( discr_val_cast, index. 0 )
665672 }
666673 DiscriminantKind :: Niche { dataful_variant, ref niche_variants, niche_start } => {
667- // Compute the variant this discriminant corresponds to. With niche layout,
668- // tag and variant index are the same.
674+ // Compute the variant this niche value/"tag" corresponds to. With niche layout,
675+ // discriminant (encoded in niche/ tag) and variant index are the same.
669676 let variants_start = niche_variants. start ( ) . as_u32 ( ) ;
670677 let variants_end = niche_variants. end ( ) . as_u32 ( ) ;
671- let variant = match discr_val . to_bits_or_ptr ( discr_layout . size , self ) {
678+ let variant = match tag_val . to_bits_or_ptr ( tag_layout . size , self ) {
672679 Err ( ptr) => {
673680 // The niche must be just 0 (which an inbounds pointer value never is)
674681 let ptr_valid = niche_start == 0
675682 && variants_start == variants_end
676683 && !self . memory . ptr_may_be_null ( ptr) ;
677684 if !ptr_valid {
678- throw_ub ! ( InvalidDiscriminant ( discr_val . erase_tag( ) ) )
685+ throw_ub ! ( InvalidDiscriminant ( tag_val . erase_tag( ) ) )
679686 }
680687 dataful_variant
681688 }
682- Ok ( bits_discr ) => {
689+ Ok ( tag_bits ) => {
683690 // We need to use machine arithmetic to get the relative variant idx:
684- // variant_index_relative = discr_val - niche_start_val
685- let discr_val = ImmTy :: from_uint ( bits_discr , discr_layout ) ;
686- let niche_start_val = ImmTy :: from_uint ( niche_start, discr_layout ) ;
691+ // variant_index_relative = tag_val - niche_start_val
692+ let tag_val = ImmTy :: from_uint ( tag_bits , tag_layout ) ;
693+ let niche_start_val = ImmTy :: from_uint ( niche_start, tag_layout ) ;
687694 let variant_index_relative_val =
688- self . binary_op ( mir:: BinOp :: Sub , discr_val , niche_start_val) ?;
695+ self . binary_op ( mir:: BinOp :: Sub , tag_val , niche_start_val) ?;
689696 let variant_index_relative = variant_index_relative_val
690697 . to_scalar ( ) ?
691- . assert_bits ( discr_val . layout . size ) ;
698+ . assert_bits ( tag_val . layout . size ) ;
692699 // Check if this is in the range that indicates an actual discriminant.
693700 if variant_index_relative <= u128:: from ( variants_end - variants_start) {
694701 let variant_index_relative = u32:: try_from ( variant_index_relative)
@@ -712,7 +719,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
712719 }
713720 } ;
714721 // Compute the size of the scalar we need to return.
715- // FIXME: Why do we not need to do a cast here like we do above?
722+ // No need to cast, because the variant index directly serves as discriminant and is
723+ // encoded in the tag.
716724 let size = self . layout_of ( discr_ty) ?. size ;
717725 ( Scalar :: from_uint ( variant. as_u32 ( ) , size) , variant)
718726 }
0 commit comments