diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0e42931b29a97..7e136c1b24cb2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1,4 +1,3 @@ -use self::EnumTagInfo::*; use self::MemberDescriptionFactory::*; use self::RecursiveTypeDescription::*; @@ -28,7 +27,7 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ich::NodeIdHashingMode; -use rustc_middle::mir::{self, Field, GeneratorLayout}; +use rustc_middle::mir::{self, GeneratorLayout}; use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::Instance; @@ -1188,7 +1187,7 @@ enum MemberDescriptionFactory<'ll, 'tcx> { TupleMDF(TupleMemberDescriptionFactory<'tcx>), EnumMDF(EnumMemberDescriptionFactory<'ll, 'tcx>), UnionMDF(UnionMemberDescriptionFactory<'tcx>), - VariantMDF(VariantMemberDescriptionFactory<'ll, 'tcx>), + VariantMDF(VariantMemberDescriptionFactory<'tcx>), } impl MemberDescriptionFactory<'ll, 'tcx> { @@ -1505,14 +1504,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } let variant_info = variant_info_for(index); - let (variant_type_metadata, member_description_factory) = describe_enum_variant( - cx, - self.layout, - variant_info, - None, - self_metadata, - self.span, - ); + let (variant_type_metadata, member_description_factory) = + describe_enum_variant(cx, self.layout, variant_info, self_metadata, self.span); let member_descriptions = member_description_factory.create_member_descriptions(cx); @@ -1524,7 +1517,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { Some(&self.common_members), ); vec![MemberDescription { - name: if fallback { String::new() } else { variant_info.variant_name() }, + name: variant_info.variant_name(), type_metadata: variant_type_metadata, offset: Size::ZERO, size: self.layout.size, @@ -1540,28 +1533,38 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { ref variants, .. } => { - let tag_info = if fallback { - // For MSVC, we generate a union of structs for each variant with an explicit - // discriminant field roughly equivalent to the following C: + let fallback_discr_variant = if fallback { + // For MSVC, we generate a union of structs for each variant and an + // explicit discriminant field roughly equivalent to the following C: // ```c // union enum$<{name}> { // struct {variant 0 name} { - // tag$ variant$; // // } variant0; // + // {name} discriminant; // } // ``` - // The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to + // The natvis in `intrinsic.natvis` then matches on `this.discriminant` to // determine which variant is active and then displays it. - Some(DirectTag { - tag_field: Field::from(tag_field), - tag_type_metadata: self.tag_type_metadata.unwrap(), + let enum_layout = self.layout; + let offset = enum_layout.fields.offset(tag_field); + let discr_ty = enum_layout.field(cx, tag_field).ty; + let (size, align) = cx.size_and_align_of(discr_ty); + Some(MemberDescription { + name: "discriminant".into(), + type_metadata: self.tag_type_metadata.unwrap(), + offset, + size, + align, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, }) } else { - // This doesn't matter in this case. None }; + variants .iter_enumerated() .map(|(i, _)| { @@ -1571,7 +1574,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - tag_info, self_metadata, self.span, ); @@ -1605,6 +1607,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { source_info: variant_info.source_info(cx), } }) + .chain(fallback_discr_variant.into_iter()) .collect() } Variants::Multiple { @@ -1702,7 +1705,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, dataful_variant_layout, variant_info, - Some(NicheTag), self_metadata, self.span, ); @@ -1754,7 +1756,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - Some(NicheTag), self_metadata, self.span, ); @@ -1791,39 +1792,27 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } // Creates `MemberDescription`s for the fields of a single enum variant. -struct VariantMemberDescriptionFactory<'ll, 'tcx> { +struct VariantMemberDescriptionFactory<'tcx> { /// Cloned from the `layout::Struct` describing the variant. offsets: Vec, args: Vec<(String, Ty<'tcx>)>, - tag_type_metadata: Option<&'ll DIType>, span: Span, } -impl VariantMemberDescriptionFactory<'ll, 'tcx> { +impl VariantMemberDescriptionFactory<'tcx> { fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec> { self.args .iter() .enumerate() .map(|(i, &(ref name, ty))| { - // Discriminant is always the first field of our variant - // when using the enum fallback. - let is_artificial_discr = use_enum_fallback(cx) && i == 0; let (size, align) = cx.size_and_align_of(ty); MemberDescription { name: name.to_string(), - type_metadata: if is_artificial_discr { - self.tag_type_metadata.unwrap_or_else(|| type_metadata(cx, ty, self.span)) - } else { - type_metadata(cx, ty, self.span) - }, + type_metadata: type_metadata(cx, ty, self.span), offset: self.offsets[i], size, align, - flags: if is_artificial_discr { - DIFlags::FlagArtificial - } else { - DIFlags::FlagZero - }, + flags: DIFlags::FlagZero, discriminant: None, source_info: None, } @@ -1832,12 +1821,6 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { } } -#[derive(Copy, Clone)] -enum EnumTagInfo<'ll> { - DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType }, - NicheTag, -} - #[derive(Copy, Clone)] enum VariantInfo<'a, 'tcx> { Adt(&'tcx ty::VariantDef), @@ -1916,7 +1899,6 @@ fn describe_enum_variant( cx: &CodegenCx<'ll, 'tcx>, layout: layout::TyAndLayout<'tcx>, variant: VariantInfo<'_, 'tcx>, - discriminant_info: Option>, containing_scope: &'ll DIScope, span: Span, ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { @@ -1935,50 +1917,13 @@ fn describe_enum_variant( ) }); - // Build an array of (field name, field type) pairs to be captured in the factory closure. - let (offsets, args) = if use_enum_fallback(cx) { - // If this is not a univariant enum, there is also the discriminant field. - let (discr_offset, discr_arg) = match discriminant_info { - Some(DirectTag { tag_field, .. }) => { - // We have the layout of an enum variant, we need the layout of the outer enum - let enum_layout = cx.layout_of(layout.ty); - let offset = enum_layout.fields.offset(tag_field.as_usize()); - let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); - (Some(offset), Some(args)) - } - _ => (None, None), - }; - ( - discr_offset - .into_iter() - .chain((0..layout.fields.count()).map(|i| layout.fields.offset(i))) - .collect(), - discr_arg - .into_iter() - .chain( - (0..layout.fields.count()) - .map(|i| (variant.field_name(i), layout.field(cx, i).ty)), - ) - .collect(), - ) - } else { - ( - (0..layout.fields.count()).map(|i| layout.fields.offset(i)).collect(), - (0..layout.fields.count()) - .map(|i| (variant.field_name(i), layout.field(cx, i).ty)) - .collect(), - ) - }; + let offsets = (0..layout.fields.count()).map(|i| layout.fields.offset(i)).collect(); + let args = (0..layout.fields.count()) + .map(|i| (variant.field_name(i), layout.field(cx, i).ty)) + .collect(); - let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { - offsets, - args, - tag_type_metadata: match discriminant_info { - Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata), - _ => None, - }, - span, - }); + let member_description_factory = + VariantMDF(VariantMemberDescriptionFactory { offsets, args, span }); (metadata_stub, member_description_factory) } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index a97c6a6b4429f..b3c14d9072cce 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -367,6 +367,10 @@ pub fn push_debuginfo_type_name<'tcx>( ) { let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error"); + output.push_str("enum$<"); + push_item_name(tcx, def.did, true, output); + push_generic_params_internal(tcx, substs, output, visited); + if let Variants::Multiple { tag_encoding: TagEncoding::Niche { dataful_variant, .. }, tag, @@ -386,19 +390,19 @@ pub fn push_debuginfo_type_name<'tcx>( let max = dataful_discriminant_range.end(); let max = tag.value.size(&tcx).truncate(*max); - output.push_str("enum$<"); - push_item_name(tcx, def.did, true, output); - push_generic_params_internal(tcx, substs, output, visited); - let dataful_variant_name = def.variants[*dataful_variant].ident.as_str(); - output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name)); - } else { - output.push_str("enum$<"); - push_item_name(tcx, def.did, true, output); - push_generic_params_internal(tcx, substs, output, visited); - push_close_angle_bracket(tcx, output); + output.push_str(&format!(", {}, {}, {}", min, max, dataful_variant_name)); + } else if let Variants::Single { index: variant_idx } = &layout.variants { + // Uninhabited enums can't be constructed and should never need to be visualized so + // skip this step for them. + if def.variants.len() != 0 { + let variant = def.variants[*variant_idx].ident.as_str(); + + output.push_str(&format!(", {}", variant)); + } } + push_close_angle_bracket(tcx, output); } } diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index cf887ffb0c01e..52e5d37c83fbd 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -149,8 +149,10 @@ ... + + - + {tag(),en} {tag(),en} {tag(),en} @@ -169,6 +171,9 @@ {tag(),en} + + {tag(),en} + variant0 variant1 variant2 @@ -188,8 +193,20 @@ - + + + {"$T2",sb} + + + {"$T2",sb} + + $T2 + + + + @@ -200,6 +217,9 @@ {"$T4",sb} + + {discriminant,en} + diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 17667770520ce..c8196d5c713b2 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -14,14 +14,6 @@ - - None - Some({($T1 *)this}) - - ($T1 *)this - - - {(void*) pointer} diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index 8efa1b15b3fff..0c16b9ad3ab51 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -43,11 +43,11 @@ async fn async_fn_test() { // CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]], -// CHECK-SAME: flags: DIFlagArtificial // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "discriminant", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial fn main() { let _dummy = async_fn_test(); diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index e2ba4ad30894d..68d138f8df2f0 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -47,11 +47,11 @@ fn generator_test() -> impl Generator { // CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]], -// CHECK-SAME: flags: DIFlagArtificial // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "discriminant", scope: [[GEN]], +// CHECK-NOT: flags: DIFlagArtificial fn main() { let _dummy = generator_test(); diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index cf3be2e719674..f248fcd839122 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -1,10 +1,14 @@ // only-cdb +// ignore-tidy-linelength // compile-flags:-g // cdb-command: g // Note: The natvis used to visualize niche-layout enums don't work correctly in cdb -// so the best we can do is to make sure we are generating the right debuginfo +// so the best we can do is to make sure we are generating the right debuginfo. +// Therefore, we use the `!` [format specifier](https://docs.microsoft.com/en-us/visualstudio/debugger/format-specifiers-in-cpp?view=vs-2019#BKMK_Visual_Studio_2012_format_specifiers) +// to disable the natvis for a given expression. We also provide the `-r2` flag +// to expand the expression 2 levels. // cdb-command: dx -r2 a,! // cdb-check:a,! [Type: enum$ >, 2, 16, Some>] @@ -48,14 +52,30 @@ // cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *] // cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$ >, 1, [...], Some>::Discriminant$] +// cdb-command: dx -r2 h,! +// cdb-check:h,! : Some [Type: enum$ >] +// cdb-check: [+0x000] variant0 [Type: enum$ >::None] +// cdb-check: [+0x000] variant1 [Type: enum$ >::Some] +// cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] +// cdb-check: [+0x000] discriminant : Some (0x1) [Type: core::option::Option] + // cdb-command: dx h // cdb-check:h : Some [Type: enum$ >] -// cdb-check: [+0x000] variant$ : Some (0x1) [Type: core::option::Option] +// cdb-check: [] [Type: enum$ >] +// cdb-check: [variant] : Some // cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] +// cdb-command: dx -r2 i,! +// cdb-check:i,! : None [Type: enum$ >] +// cdb-check: [+0x000] variant0 [Type: enum$ >::None] +// cdb-check: [+0x000] variant1 [Type: enum$ >::Some] +// cdb-check: [+0x004] __0 : 0x[...] [Type: unsigned int] +// cdb-check: [+0x000] discriminant : None (0x0) [Type: core::option::Option] + // cdb-command: dx i // cdb-check:i : None [Type: enum$ >] -// cdb-check: [+0x000] variant$ : None (0x0) [Type: core::option::Option] +// cdb-check: [] [Type: enum$ >] +// cdb-check: [variant] : None // cdb-command: dx j // cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] @@ -66,6 +86,11 @@ // cdb-check: [+0x000] __0 [Type: alloc::string::String] // cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$, 1, [...], Some>::Discriminant$] +// cdb-command: dx -r2 l,! +// cdb-check:l,! : $T2 [Type: enum$ >, Ok>] +// cdb-check: [+0x000] Ok [Type: enum$ >, Ok>::Ok] +// cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] + pub enum CStyleEnum { Low = 2, High = 16, @@ -77,6 +102,8 @@ pub enum NicheLayoutEnum { Tag2, } +pub enum Empty { } + fn main() { let a = Some(CStyleEnum::Low); let b = Option::::None; @@ -89,6 +116,7 @@ fn main() { let i = Option::::None; let j = CStyleEnum::High; let k = Some("IAMA optional string!".to_string()); + let l = Result::::Ok(42); zzz(); // #break } diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index a7f384c05007d..7ed76beb8c6d9 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -116,12 +116,14 @@ // cdb-command: dx some // cdb-check:some : Some [Type: enum$ >] -// cdb-check: [...] variant$ : Some (0x1) [Type: core::option::Option] -// cdb-check: [...] __0 : 8 [Type: short] +// cdb-check: [] [Type: enum$ >] +// cdb-check: [variant] : Some +// cdb-check: [+0x002] __0 : 8 [Type: short] // cdb-command: dx none // cdb-check:none : None [Type: enum$ >] -// cdb-check: [...] variant$ : None (0x0) [Type: core::option::Option] +// cdb-check: [] [Type: enum$ >] +// cdb-check: [variant] : None // cdb-command: dx some_string // NOTE: cdb fails to interpret debug info of Option enums on i686.