@@ -580,7 +580,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
580
580
) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , VariantIdx ) > {
581
581
trace ! ( "read_discriminant_value {:#?}" , rval. layout) ;
582
582
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 {
584
591
Variants :: Single { index } => {
585
592
let discr = match rval. layout . ty . discriminant_for_variant ( * self . tcx , index) {
586
593
Some ( discr) => {
@@ -602,31 +609,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
602
609
} ;
603
610
604
611
// 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 .
613
620
614
621
// 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 ) ) ?;
616
623
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 ) ;
623
630
624
631
// Get type used by typechecking.
625
632
let discr_ty = match rval. layout . ty . kind {
626
633
ty:: Adt ( adt, _) => {
627
634
let discr_int_ty = Integer :: from_attr ( self , adt. repr . discr_type ( ) ) ;
628
635
// 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 ( ) )
630
637
}
631
638
ty:: Generator ( _, substs, _) => {
632
639
let substs = substs. as_generator ( ) ;
@@ -636,17 +643,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
636
643
} ;
637
644
638
645
// Figure out which discriminant and variant this corresponds to.
639
- Ok ( match * discr_kind {
646
+ Ok ( match * tag_kind {
640
647
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) ?;
646
653
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.
650
657
let index = match rval. layout . ty . kind {
651
658
ty:: Adt ( adt, _) => {
652
659
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> {
659
666
}
660
667
_ => bug ! ( "tagged layout for non-adt non-generator" ) ,
661
668
}
662
- . ok_or_else ( || err_ub ! ( InvalidDiscriminant ( discr_val . erase_tag( ) ) ) ) ?;
669
+ . ok_or_else ( || err_ub ! ( InvalidDiscriminant ( tag_val . erase_tag( ) ) ) ) ?;
663
670
// Return the cast value, and the index.
664
671
( discr_val_cast, index. 0 )
665
672
}
666
673
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.
669
676
let variants_start = niche_variants. start ( ) . as_u32 ( ) ;
670
677
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 ) {
672
679
Err ( ptr) => {
673
680
// The niche must be just 0 (which an inbounds pointer value never is)
674
681
let ptr_valid = niche_start == 0
675
682
&& variants_start == variants_end
676
683
&& !self . memory . ptr_may_be_null ( ptr) ;
677
684
if !ptr_valid {
678
- throw_ub ! ( InvalidDiscriminant ( discr_val . erase_tag( ) ) )
685
+ throw_ub ! ( InvalidDiscriminant ( tag_val . erase_tag( ) ) )
679
686
}
680
687
dataful_variant
681
688
}
682
- Ok ( bits_discr ) => {
689
+ Ok ( tag_bits ) => {
683
690
// 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 ) ;
687
694
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) ?;
689
696
let variant_index_relative = variant_index_relative_val
690
697
. to_scalar ( ) ?
691
- . assert_bits ( discr_val . layout . size ) ;
698
+ . assert_bits ( tag_val . layout . size ) ;
692
699
// Check if this is in the range that indicates an actual discriminant.
693
700
if variant_index_relative <= u128:: from ( variants_end - variants_start) {
694
701
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> {
712
719
}
713
720
} ;
714
721
// 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.
716
724
let size = self . layout_of ( discr_ty) ?. size ;
717
725
( Scalar :: from_uint ( variant. as_u32 ( ) , size) , variant)
718
726
}
0 commit comments