@@ -1594,77 +1594,144 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
1594
1594
ref variants,
1595
1595
tag_field,
1596
1596
} => {
1597
+ let calculate_niche_value = |i : VariantIdx | {
1598
+ if i == dataful_variant {
1599
+ None
1600
+ } else {
1601
+ let value = ( i. as_u32 ( ) as u128 )
1602
+ . wrapping_sub ( niche_variants. start ( ) . as_u32 ( ) as u128 )
1603
+ . wrapping_add ( niche_start) ;
1604
+ let value = tag. value . size ( cx) . truncate ( value) ;
1605
+ // NOTE(eddyb) do *NOT* remove this assert, until
1606
+ // we pass the full 128-bit value to LLVM, otherwise
1607
+ // truncation will be silent and remain undetected.
1608
+ assert_eq ! ( value as u64 as u128 , value) ;
1609
+ Some ( value as u64 )
1610
+ }
1611
+ } ;
1612
+
1613
+ // For MSVC, we will generate a union of two structs, one for the dataful variant and one that just points to
1614
+ // the discriminant field. We also create an enum that contains tag values for the non-dataful variants and
1615
+ // make the discriminant field that type. We then use natvis to render the enum type correctly in Windbg/VS.
1597
1616
if fallback {
1598
- let variant = self . layout . for_variant ( cx, dataful_variant) ;
1599
- // Create a description of the non-null variant.
1600
- let ( variant_type_metadata, member_description_factory) = describe_enum_variant (
1617
+ let unique_type_id = debug_context ( cx)
1618
+ . type_map
1619
+ . borrow_mut ( )
1620
+ . get_unique_type_id_of_enum_variant ( cx, self . enum_type , "discriminant$" ) ;
1621
+
1622
+ let variant_metadata = create_struct_stub (
1623
+ cx,
1624
+ self . layout . ty ,
1625
+ & "discriminant$" ,
1626
+ unique_type_id,
1627
+ Some ( self_metadata) ,
1628
+ DIFlags :: FlagArtificial ,
1629
+ ) ;
1630
+
1631
+ let dataful_variant_layout = self . layout . for_variant ( cx, dataful_variant) ;
1632
+
1633
+ let mut discr_enum_ty = tag. value . to_ty ( cx. tcx ) ;
1634
+ // If the niche is the NULL value of a reference, then `discr_enum_ty` will be a RawPtr.
1635
+ // CodeView doesn't know what to do with enums whose base type is a pointer so we fix this up
1636
+ // to just be `usize`.
1637
+ if let ty:: RawPtr ( _) = discr_enum_ty. kind ( ) {
1638
+ discr_enum_ty = cx. tcx . types . usize ;
1639
+ }
1640
+
1641
+ let tags: Vec < _ > = variants
1642
+ . iter_enumerated ( )
1643
+ . filter_map ( |( variant_idx, _) | {
1644
+ calculate_niche_value ( variant_idx) . map ( |tag| {
1645
+ let variant = variant_info_for ( variant_idx) ;
1646
+ let name = variant. variant_name ( ) ;
1647
+
1648
+ Some ( unsafe {
1649
+ llvm:: LLVMRustDIBuilderCreateEnumerator (
1650
+ DIB ( cx) ,
1651
+ name. as_ptr ( ) . cast ( ) ,
1652
+ name. len ( ) ,
1653
+ tag as i64 ,
1654
+ !discr_enum_ty. is_signed ( ) ,
1655
+ )
1656
+ } )
1657
+ } )
1658
+ } )
1659
+ . collect ( ) ;
1660
+
1661
+ let discr_enum = unsafe {
1662
+ llvm:: LLVMRustDIBuilderCreateEnumerationType (
1663
+ DIB ( cx) ,
1664
+ self_metadata,
1665
+ "tag$" . as_ptr ( ) . cast ( ) ,
1666
+ "tag$" . len ( ) ,
1667
+ unknown_file_metadata ( cx) ,
1668
+ UNKNOWN_LINE_NUMBER ,
1669
+ tag. value . size ( cx) . bits ( ) ,
1670
+ tag. value . align ( cx) . abi . bits ( ) as u32 ,
1671
+ create_DIArray ( DIB ( cx) , & tags) ,
1672
+ type_metadata ( cx, discr_enum_ty, self . span ) ,
1673
+ true ,
1674
+ )
1675
+ } ;
1676
+
1677
+ let ( size, align) =
1678
+ cx. size_and_align_of ( dataful_variant_layout. field ( cx, tag_field) . ty ) ;
1679
+ let members = vec ! [ MemberDescription {
1680
+ name: "discriminant" . to_string( ) ,
1681
+ type_metadata: discr_enum,
1682
+ offset: dataful_variant_layout. fields. offset( tag_field) ,
1683
+ size,
1684
+ align,
1685
+ flags: DIFlags :: FlagArtificial ,
1686
+ discriminant: None ,
1687
+ source_info: None ,
1688
+ } ] ;
1689
+
1690
+ set_members_of_composite_type ( cx, self . enum_type , variant_metadata, members, None ) ;
1691
+
1692
+ let variant_info = variant_info_for ( dataful_variant) ;
1693
+ let ( variant_type_metadata, member_desc_factory) = describe_enum_variant (
1601
1694
cx,
1602
- variant ,
1603
- variant_info_for ( dataful_variant ) ,
1695
+ dataful_variant_layout ,
1696
+ variant_info ,
1604
1697
Some ( NicheTag ) ,
1605
1698
self_metadata,
1606
1699
self . span ,
1607
1700
) ;
1608
1701
1609
- let variant_member_descriptions =
1610
- member_description_factory. create_member_descriptions ( cx) ;
1702
+ let member_descriptions = member_desc_factory. create_member_descriptions ( cx) ;
1611
1703
1612
1704
set_members_of_composite_type (
1613
1705
cx,
1614
1706
self . enum_type ,
1615
1707
variant_type_metadata,
1616
- variant_member_descriptions ,
1708
+ member_descriptions ,
1617
1709
Some ( & self . common_members ) ,
1618
1710
) ;
1619
1711
1620
- // Encode the information about the null variant in the union
1621
- // member's name.
1622
- let mut name = String :: from ( "RUST$ENCODED$ENUM$" ) ;
1623
- // Right now it's not even going to work for `niche_start > 0`,
1624
- // and for multiple niche variants it only supports the first.
1625
- fn compute_field_path < ' a , ' tcx > (
1626
- cx : & CodegenCx < ' a , ' tcx > ,
1627
- name : & mut String ,
1628
- layout : TyAndLayout < ' tcx > ,
1629
- offset : Size ,
1630
- size : Size ,
1631
- ) {
1632
- for i in 0 ..layout. fields . count ( ) {
1633
- let field_offset = layout. fields . offset ( i) ;
1634
- if field_offset > offset {
1635
- continue ;
1636
- }
1637
- let inner_offset = offset - field_offset;
1638
- let field = layout. field ( cx, i) ;
1639
- if inner_offset + size <= field. size {
1640
- write ! ( name, "{}$" , i) . unwrap ( ) ;
1641
- compute_field_path ( cx, name, field, inner_offset, size) ;
1642
- }
1643
- }
1644
- }
1645
- compute_field_path (
1646
- cx,
1647
- & mut name,
1648
- self . layout ,
1649
- self . layout . fields . offset ( tag_field) ,
1650
- self . layout . field ( cx, tag_field) . size ,
1651
- ) ;
1652
- let variant_info = variant_info_for ( * niche_variants. start ( ) ) ;
1653
- variant_info. map_struct_name ( |variant_name| {
1654
- name. push_str ( variant_name) ;
1655
- } ) ;
1656
-
1657
- // Create the (singleton) list of descriptions of union members.
1658
- vec ! [ MemberDescription {
1659
- name,
1660
- type_metadata: variant_type_metadata,
1661
- offset: Size :: ZERO ,
1662
- size: variant. size,
1663
- align: variant. align. abi,
1664
- flags: DIFlags :: FlagZero ,
1665
- discriminant: None ,
1666
- source_info: variant_info. source_info( cx) ,
1667
- } ]
1712
+ vec ! [
1713
+ MemberDescription {
1714
+ // Name the dataful variant so that we can identify it for natvis
1715
+ name: "dataful_variant" . to_string( ) ,
1716
+ type_metadata: variant_type_metadata,
1717
+ offset: Size :: ZERO ,
1718
+ size: self . layout. size,
1719
+ align: self . layout. align. abi,
1720
+ flags: DIFlags :: FlagZero ,
1721
+ discriminant: None ,
1722
+ source_info: variant_info. source_info( cx) ,
1723
+ } ,
1724
+ MemberDescription {
1725
+ name: "discriminant$" . into( ) ,
1726
+ type_metadata: variant_metadata,
1727
+ offset: Size :: ZERO ,
1728
+ size: self . layout. size,
1729
+ align: self . layout. align. abi,
1730
+ flags: DIFlags :: FlagZero ,
1731
+ discriminant: None ,
1732
+ source_info: None ,
1733
+ } ,
1734
+ ]
1668
1735
} else {
1669
1736
variants
1670
1737
. iter_enumerated ( )
@@ -1692,19 +1759,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
1692
1759
Some ( & self . common_members ) ,
1693
1760
) ;
1694
1761
1695
- let niche_value = if i == dataful_variant {
1696
- None
1697
- } else {
1698
- let value = ( i. as_u32 ( ) as u128 )
1699
- . wrapping_sub ( niche_variants. start ( ) . as_u32 ( ) as u128 )
1700
- . wrapping_add ( niche_start) ;
1701
- let value = tag. value . size ( cx) . truncate ( value) ;
1702
- // NOTE(eddyb) do *NOT* remove this assert, until
1703
- // we pass the full 128-bit value to LLVM, otherwise
1704
- // truncation will be silent and remain undetected.
1705
- assert_eq ! ( value as u64 as u128 , value) ;
1706
- Some ( value as u64 )
1707
- } ;
1762
+ let niche_value = calculate_niche_value ( i) ;
1708
1763
1709
1764
MemberDescription {
1710
1765
name : variant_info. variant_name ( ) ,
@@ -2040,9 +2095,9 @@ fn prepare_enum_metadata(
2040
2095
2041
2096
if use_enum_fallback ( cx) {
2042
2097
let discriminant_type_metadata = match layout. variants {
2043
- Variants :: Single { .. }
2044
- | Variants :: Multiple { tag_encoding : TagEncoding :: Niche { .. } , .. } => None ,
2045
- Variants :: Multiple { tag_encoding : TagEncoding :: Direct , ref tag, .. } => {
2098
+ Variants :: Single { .. } => None ,
2099
+ Variants :: Multiple { tag_encoding : TagEncoding :: Niche { .. } , ref tag , .. }
2100
+ | Variants :: Multiple { tag_encoding : TagEncoding :: Direct , ref tag, .. } => {
2046
2101
Some ( discriminant_type_metadata ( tag. value ) )
2047
2102
}
2048
2103
} ;
0 commit comments