@@ -1594,77 +1594,144 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
15941594 ref variants,
15951595 tag_field,
15961596 } => {
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.
15971616 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 (
16011694 cx,
1602- variant ,
1603- variant_info_for ( dataful_variant ) ,
1695+ dataful_variant_layout ,
1696+ variant_info ,
16041697 Some ( NicheTag ) ,
16051698 self_metadata,
16061699 self . span ,
16071700 ) ;
16081701
1609- let variant_member_descriptions =
1610- member_description_factory. create_member_descriptions ( cx) ;
1702+ let member_descriptions = member_desc_factory. create_member_descriptions ( cx) ;
16111703
16121704 set_members_of_composite_type (
16131705 cx,
16141706 self . enum_type ,
16151707 variant_type_metadata,
1616- variant_member_descriptions ,
1708+ member_descriptions ,
16171709 Some ( & self . common_members ) ,
16181710 ) ;
16191711
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+ ]
16681735 } else {
16691736 variants
16701737 . iter_enumerated ( )
@@ -1692,19 +1759,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
16921759 Some ( & self . common_members ) ,
16931760 ) ;
16941761
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) ;
17081763
17091764 MemberDescription {
17101765 name : variant_info. variant_name ( ) ,
@@ -2040,9 +2095,9 @@ fn prepare_enum_metadata(
20402095
20412096 if use_enum_fallback ( cx) {
20422097 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, .. } => {
20462101 Some ( discriminant_type_metadata ( tag. value ) )
20472102 }
20482103 } ;
0 commit comments