Skip to content

Commit 8853999

Browse files
committed
Auto merge of #86636 - wesleywiser:misc_enum_improvements, r=michaelwoerister
[msvc] Consistently show active variant and fix visualization for single variant enums Prior to this change, there were a few cases where inspecting an enum in either WinDbg or Visual Studio would not show the active variant name. After these changes, we now consistently show the active variant name as `[variant]` in the debugger. We also didn't handle single variant enums very well. That is now also resolved. Before: ![image](https://user-images.githubusercontent.com/831192/123480097-dc8b5f00-d5cf-11eb-93a8-9fc05a97029b.png) After: ![image](https://user-images.githubusercontent.com/831192/123479966-aa79fd00-d5cf-11eb-955e-9798616a8829.png) r? `@michaelwoerister`
2 parents 238fd72 + 457165e commit 8853999

File tree

8 files changed

+112
-121
lines changed

8 files changed

+112
-121
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+35-90
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use self::EnumTagInfo::*;
21
use self::MemberDescriptionFactory::*;
32
use self::RecursiveTypeDescription::*;
43

@@ -28,7 +27,7 @@ use rustc_hir::def::CtorKind;
2827
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
2928
use rustc_index::vec::{Idx, IndexVec};
3029
use rustc_middle::ich::NodeIdHashingMode;
31-
use rustc_middle::mir::{self, Field, GeneratorLayout};
30+
use rustc_middle::mir::{self, GeneratorLayout};
3231
use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout};
3332
use rustc_middle::ty::subst::GenericArgKind;
3433
use rustc_middle::ty::Instance;
@@ -1188,7 +1187,7 @@ enum MemberDescriptionFactory<'ll, 'tcx> {
11881187
TupleMDF(TupleMemberDescriptionFactory<'tcx>),
11891188
EnumMDF(EnumMemberDescriptionFactory<'ll, 'tcx>),
11901189
UnionMDF(UnionMemberDescriptionFactory<'tcx>),
1191-
VariantMDF(VariantMemberDescriptionFactory<'ll, 'tcx>),
1190+
VariantMDF(VariantMemberDescriptionFactory<'tcx>),
11921191
}
11931192

11941193
impl MemberDescriptionFactory<'ll, 'tcx> {
@@ -1505,14 +1504,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
15051504
}
15061505

15071506
let variant_info = variant_info_for(index);
1508-
let (variant_type_metadata, member_description_factory) = describe_enum_variant(
1509-
cx,
1510-
self.layout,
1511-
variant_info,
1512-
None,
1513-
self_metadata,
1514-
self.span,
1515-
);
1507+
let (variant_type_metadata, member_description_factory) =
1508+
describe_enum_variant(cx, self.layout, variant_info, self_metadata, self.span);
15161509

15171510
let member_descriptions = member_description_factory.create_member_descriptions(cx);
15181511

@@ -1524,7 +1517,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
15241517
Some(&self.common_members),
15251518
);
15261519
vec![MemberDescription {
1527-
name: if fallback { String::new() } else { variant_info.variant_name() },
1520+
name: variant_info.variant_name(),
15281521
type_metadata: variant_type_metadata,
15291522
offset: Size::ZERO,
15301523
size: self.layout.size,
@@ -1540,28 +1533,38 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
15401533
ref variants,
15411534
..
15421535
} => {
1543-
let tag_info = if fallback {
1544-
// For MSVC, we generate a union of structs for each variant with an explicit
1545-
// discriminant field roughly equivalent to the following C:
1536+
let fallback_discr_variant = if fallback {
1537+
// For MSVC, we generate a union of structs for each variant and an
1538+
// explicit discriminant field roughly equivalent to the following C:
15461539
// ```c
15471540
// union enum$<{name}> {
15481541
// struct {variant 0 name} {
1549-
// tag$ variant$;
15501542
// <variant 0 fields>
15511543
// } variant0;
15521544
// <other variant structs>
1545+
// {name} discriminant;
15531546
// }
15541547
// ```
1555-
// The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to
1548+
// The natvis in `intrinsic.natvis` then matches on `this.discriminant` to
15561549
// determine which variant is active and then displays it.
1557-
Some(DirectTag {
1558-
tag_field: Field::from(tag_field),
1559-
tag_type_metadata: self.tag_type_metadata.unwrap(),
1550+
let enum_layout = self.layout;
1551+
let offset = enum_layout.fields.offset(tag_field);
1552+
let discr_ty = enum_layout.field(cx, tag_field).ty;
1553+
let (size, align) = cx.size_and_align_of(discr_ty);
1554+
Some(MemberDescription {
1555+
name: "discriminant".into(),
1556+
type_metadata: self.tag_type_metadata.unwrap(),
1557+
offset,
1558+
size,
1559+
align,
1560+
flags: DIFlags::FlagZero,
1561+
discriminant: None,
1562+
source_info: None,
15601563
})
15611564
} else {
1562-
// This doesn't matter in this case.
15631565
None
15641566
};
1567+
15651568
variants
15661569
.iter_enumerated()
15671570
.map(|(i, _)| {
@@ -1571,7 +1574,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
15711574
cx,
15721575
variant,
15731576
variant_info,
1574-
tag_info,
15751577
self_metadata,
15761578
self.span,
15771579
);
@@ -1605,6 +1607,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
16051607
source_info: variant_info.source_info(cx),
16061608
}
16071609
})
1610+
.chain(fallback_discr_variant.into_iter())
16081611
.collect()
16091612
}
16101613
Variants::Multiple {
@@ -1702,7 +1705,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
17021705
cx,
17031706
dataful_variant_layout,
17041707
variant_info,
1705-
Some(NicheTag),
17061708
self_metadata,
17071709
self.span,
17081710
);
@@ -1754,7 +1756,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
17541756
cx,
17551757
variant,
17561758
variant_info,
1757-
Some(NicheTag),
17581759
self_metadata,
17591760
self.span,
17601761
);
@@ -1791,39 +1792,27 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
17911792
}
17921793

17931794
// Creates `MemberDescription`s for the fields of a single enum variant.
1794-
struct VariantMemberDescriptionFactory<'ll, 'tcx> {
1795+
struct VariantMemberDescriptionFactory<'tcx> {
17951796
/// Cloned from the `layout::Struct` describing the variant.
17961797
offsets: Vec<Size>,
17971798
args: Vec<(String, Ty<'tcx>)>,
1798-
tag_type_metadata: Option<&'ll DIType>,
17991799
span: Span,
18001800
}
18011801

1802-
impl VariantMemberDescriptionFactory<'ll, 'tcx> {
1802+
impl VariantMemberDescriptionFactory<'tcx> {
18031803
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
18041804
self.args
18051805
.iter()
18061806
.enumerate()
18071807
.map(|(i, &(ref name, ty))| {
1808-
// Discriminant is always the first field of our variant
1809-
// when using the enum fallback.
1810-
let is_artificial_discr = use_enum_fallback(cx) && i == 0;
18111808
let (size, align) = cx.size_and_align_of(ty);
18121809
MemberDescription {
18131810
name: name.to_string(),
1814-
type_metadata: if is_artificial_discr {
1815-
self.tag_type_metadata.unwrap_or_else(|| type_metadata(cx, ty, self.span))
1816-
} else {
1817-
type_metadata(cx, ty, self.span)
1818-
},
1811+
type_metadata: type_metadata(cx, ty, self.span),
18191812
offset: self.offsets[i],
18201813
size,
18211814
align,
1822-
flags: if is_artificial_discr {
1823-
DIFlags::FlagArtificial
1824-
} else {
1825-
DIFlags::FlagZero
1826-
},
1815+
flags: DIFlags::FlagZero,
18271816
discriminant: None,
18281817
source_info: None,
18291818
}
@@ -1832,12 +1821,6 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
18321821
}
18331822
}
18341823

1835-
#[derive(Copy, Clone)]
1836-
enum EnumTagInfo<'ll> {
1837-
DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType },
1838-
NicheTag,
1839-
}
1840-
18411824
#[derive(Copy, Clone)]
18421825
enum VariantInfo<'a, 'tcx> {
18431826
Adt(&'tcx ty::VariantDef),
@@ -1916,7 +1899,6 @@ fn describe_enum_variant(
19161899
cx: &CodegenCx<'ll, 'tcx>,
19171900
layout: layout::TyAndLayout<'tcx>,
19181901
variant: VariantInfo<'_, 'tcx>,
1919-
discriminant_info: Option<EnumTagInfo<'ll>>,
19201902
containing_scope: &'ll DIScope,
19211903
span: Span,
19221904
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
@@ -1935,50 +1917,13 @@ fn describe_enum_variant(
19351917
)
19361918
});
19371919

1938-
// Build an array of (field name, field type) pairs to be captured in the factory closure.
1939-
let (offsets, args) = if use_enum_fallback(cx) {
1940-
// If this is not a univariant enum, there is also the discriminant field.
1941-
let (discr_offset, discr_arg) = match discriminant_info {
1942-
Some(DirectTag { tag_field, .. }) => {
1943-
// We have the layout of an enum variant, we need the layout of the outer enum
1944-
let enum_layout = cx.layout_of(layout.ty);
1945-
let offset = enum_layout.fields.offset(tag_field.as_usize());
1946-
let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
1947-
(Some(offset), Some(args))
1948-
}
1949-
_ => (None, None),
1950-
};
1951-
(
1952-
discr_offset
1953-
.into_iter()
1954-
.chain((0..layout.fields.count()).map(|i| layout.fields.offset(i)))
1955-
.collect(),
1956-
discr_arg
1957-
.into_iter()
1958-
.chain(
1959-
(0..layout.fields.count())
1960-
.map(|i| (variant.field_name(i), layout.field(cx, i).ty)),
1961-
)
1962-
.collect(),
1963-
)
1964-
} else {
1965-
(
1966-
(0..layout.fields.count()).map(|i| layout.fields.offset(i)).collect(),
1967-
(0..layout.fields.count())
1968-
.map(|i| (variant.field_name(i), layout.field(cx, i).ty))
1969-
.collect(),
1970-
)
1971-
};
1920+
let offsets = (0..layout.fields.count()).map(|i| layout.fields.offset(i)).collect();
1921+
let args = (0..layout.fields.count())
1922+
.map(|i| (variant.field_name(i), layout.field(cx, i).ty))
1923+
.collect();
19721924

1973-
let member_description_factory = VariantMDF(VariantMemberDescriptionFactory {
1974-
offsets,
1975-
args,
1976-
tag_type_metadata: match discriminant_info {
1977-
Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata),
1978-
_ => None,
1979-
},
1980-
span,
1981-
});
1925+
let member_description_factory =
1926+
VariantMDF(VariantMemberDescriptionFactory { offsets, args, span });
19821927

19831928
(metadata_stub, member_description_factory)
19841929
}

compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,10 @@ pub fn push_debuginfo_type_name<'tcx>(
367367
) {
368368
let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error");
369369

370+
output.push_str("enum$<");
371+
push_item_name(tcx, def.did, true, output);
372+
push_generic_params_internal(tcx, substs, output, visited);
373+
370374
if let Variants::Multiple {
371375
tag_encoding: TagEncoding::Niche { dataful_variant, .. },
372376
tag,
@@ -386,19 +390,19 @@ pub fn push_debuginfo_type_name<'tcx>(
386390
let max = dataful_discriminant_range.end();
387391
let max = tag.value.size(&tcx).truncate(*max);
388392

389-
output.push_str("enum$<");
390-
push_item_name(tcx, def.did, true, output);
391-
push_generic_params_internal(tcx, substs, output, visited);
392-
393393
let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
394394

395-
output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name));
396-
} else {
397-
output.push_str("enum$<");
398-
push_item_name(tcx, def.did, true, output);
399-
push_generic_params_internal(tcx, substs, output, visited);
400-
push_close_angle_bracket(tcx, output);
395+
output.push_str(&format!(", {}, {}, {}", min, max, dataful_variant_name));
396+
} else if let Variants::Single { index: variant_idx } = &layout.variants {
397+
// Uninhabited enums can't be constructed and should never need to be visualized so
398+
// skip this step for them.
399+
if def.variants.len() != 0 {
400+
let variant = def.variants[*variant_idx].ident.as_str();
401+
402+
output.push_str(&format!(", {}", variant));
403+
}
401404
}
405+
push_close_angle_bracket(tcx, output);
402406
}
403407
}
404408

src/etc/natvis/intrinsic.natvis

+23-3
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,10 @@
149149
<Synthetic Name="[...]"><DisplayString>...</DisplayString></Synthetic>
150150
</Expand>
151151
</Type>
152+
153+
<!-- Directly tagged enums. $T1 is the type name -->
152154
<Type Name="enum$&lt;*&gt;">
153-
<Intrinsic Name="tag" Expression="variant0.variant$" />
155+
<Intrinsic Name="tag" Expression="discriminant" />
154156
<DisplayString Condition="tag() == 0">{tag(),en}</DisplayString>
155157
<DisplayString Condition="tag() == 1" Optional="true">{tag(),en}</DisplayString>
156158
<DisplayString Condition="tag() == 2" Optional="true">{tag(),en}</DisplayString>
@@ -169,6 +171,9 @@
169171
<DisplayString Condition="tag() == 15" Optional="true">{tag(),en}</DisplayString>
170172

171173
<Expand>
174+
<Synthetic Name="[variant]">
175+
<DisplayString>{tag(),en}</DisplayString>
176+
</Synthetic>
172177
<ExpandedItem Condition="tag() == 0">variant0</ExpandedItem>
173178
<ExpandedItem Condition="tag() == 1" Optional="true">variant1</ExpandedItem>
174179
<ExpandedItem Condition="tag() == 2" Optional="true">variant2</ExpandedItem>
@@ -188,8 +193,20 @@
188193
</Expand>
189194
</Type>
190195

191-
<!-- $T1 is the name of the enum, $T2 is the low value of the dataful variant tag,
192-
$T3 is the high value of the dataful variant tag, $T4 is the name of the dataful variant -->
196+
<!-- Single variant enums. $T1 is the name of the enum, $T2 is the name of the variant -->
197+
<Type Name="enum$&lt;*, *&gt;">
198+
<DisplayString>{"$T2",sb}</DisplayString>
199+
<Expand>
200+
<Synthetic Name="[variant]">
201+
<DisplayString>{"$T2",sb}</DisplayString>
202+
</Synthetic>
203+
<ExpandedItem>$T2</ExpandedItem>
204+
</Expand>
205+
</Type>
206+
207+
<!-- Niche-layout enums. $T1 is the name of the enum, $T2 is the low value of the dataful
208+
variant tag, $T3 is the high value of the dataful variant tag, $T4 is the name of
209+
the dataful variant -->
193210
<Type Name="enum$&lt;*, *, *, *&gt;">
194211
<Intrinsic Name="tag" Expression="discriminant" />
195212
<Intrinsic Name="is_dataful" Expression="tag() &gt;= $T2 &amp;&amp; tag() &lt;= $T3" />
@@ -200,6 +217,9 @@
200217
<Synthetic Condition="is_dataful()" Name="[variant]">
201218
<DisplayString>{"$T4",sb}</DisplayString>
202219
</Synthetic>
220+
<Synthetic Condition="!is_dataful()" Name="[variant]">
221+
<DisplayString>{discriminant,en}</DisplayString>
222+
</Synthetic>
203223
</Expand>
204224
</Type>
205225
</AutoVisualizer>

src/etc/natvis/libcore.natvis

-8
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@
1414
</Expand>
1515
</Type>
1616

17-
<Type Name="core::option::Option&lt;*&gt;" Priority="MediumLow">
18-
<DisplayString Condition="*(void**)this == nullptr">None</DisplayString>
19-
<DisplayString>Some({($T1 *)this})</DisplayString>
20-
<Expand>
21-
<Item Name="Some" ExcludeView="simple" Condition="*(void**)this != nullptr">($T1 *)this</Item>
22-
</Expand>
23-
</Type>
24-
2517
<Type Name="core::ptr::non_null::NonNull&lt;*&gt;">
2618
<DisplayString>{(void*) pointer}</DisplayString>
2719
<Expand>

src/test/codegen/async-fn-debug-msvc.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ async fn async_fn_test() {
4343
// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
4444
// CHECK-NOT: flags: DIFlagArtificial
4545
// CHECK-SAME: )
46-
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
47-
// CHECK-SAME: flags: DIFlagArtificial
4846
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
4947
// CHECK-NOT: flags: DIFlagArtificial
5048
// CHECK-SAME: )
49+
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "discriminant", scope: [[GEN]],
50+
// CHECK-NOT: flags: DIFlagArtificial
5151

5252
fn main() {
5353
let _dummy = async_fn_test();

src/test/codegen/generator-debug-msvc.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
4747
// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
4848
// CHECK-NOT: flags: DIFlagArtificial
4949
// CHECK-SAME: )
50-
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
51-
// CHECK-SAME: flags: DIFlagArtificial
5250
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
5351
// CHECK-NOT: flags: DIFlagArtificial
5452
// CHECK-SAME: )
53+
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "discriminant", scope: [[GEN]],
54+
// CHECK-NOT: flags: DIFlagArtificial
5555

5656
fn main() {
5757
let _dummy = generator_test();

0 commit comments

Comments
 (0)