Skip to content

Commit 0e75fe9

Browse files
committed
Auto merge of rust-lang#128037 - beetrees:repr128-c-style-use-natvis, r=michaelwoerister
Use the `enum2$` Natvis visualiser for repr128 C-style enums Use the preexisting `enum2$` Natvis visualiser to allow PDB debuggers to display fieldless `#[repr(u128)]]`/`#[repr(i128)]]` enums correctly. Tracking issue: rust-lang#56071 try-job: x86_64-msvc
2 parents 355a307 + fe4fa2f commit 0e75fe9

File tree

6 files changed

+136
-67
lines changed

6 files changed

+136
-67
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::borrow::Cow;
22

33
use libc::c_uint;
44
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
5-
use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
5+
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
66
use rustc_codegen_ssa::traits::ConstMethods;
77
use rustc_index::IndexVec;
88
use rustc_middle::bug;
@@ -12,7 +12,7 @@ use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};
1212
use smallvec::smallvec;
1313

1414
use crate::common::CodegenCx;
15-
use crate::debuginfo::metadata::enums::{tag_base_type, DiscrResult};
15+
use crate::debuginfo::metadata::enums::DiscrResult;
1616
use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
1717
use crate::debuginfo::metadata::{
1818
build_field_di_node, file_metadata, size_and_align_of, type_di_node, unknown_file_metadata,
@@ -190,7 +190,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
190190
let enum_type_and_layout = cx.layout_of(enum_type);
191191
let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
192192

193-
assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
193+
assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
194194

195195
type_map::build_type_with_children(
196196
cx,
@@ -265,7 +265,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
265265
let coroutine_type_and_layout = cx.layout_of(coroutine_type);
266266
let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
267267

268-
assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
268+
assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));
269269

270270
type_map::build_type_with_children(
271271
cx,
@@ -381,7 +381,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
381381
tag_field: usize,
382382
untagged_variant_index: Option<VariantIdx>,
383383
) -> SmallVec<&'ll DIType> {
384-
let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
384+
let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
385385

386386
let variant_names_type_di_node = build_variant_names_type_di_node(
387387
cx,
@@ -676,7 +676,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
676676
let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);
677677
let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len();
678678

679-
let tag_base_type = tag_base_type(cx, coroutine_type_and_layout);
679+
let tag_base_type = tag_base_type(cx.tcx, coroutine_type_and_layout);
680680

681681
let variant_names_type_di_node = build_variant_names_type_di_node(
682682
cx,
@@ -803,7 +803,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
803803

804804
assert_eq!(
805805
cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
806-
cx.size_and_align_of(super::tag_base_type(cx, enum_type_and_layout))
806+
cx.size_and_align_of(self::tag_base_type(cx.tcx, enum_type_and_layout))
807807
);
808808

809809
// ... and a field for the tag. If the tag is 128 bits wide, this will actually

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs

+5-49
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
use std::borrow::Cow;
22

33
use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_like_debuginfo};
4-
use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
4+
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
55
use rustc_hir::def::CtorKind;
66
use rustc_index::IndexSlice;
77
use rustc_middle::bug;
88
use rustc_middle::mir::CoroutineLayout;
9-
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
9+
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
1010
use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef};
1111
use rustc_span::Symbol;
12-
use rustc_target::abi::{
13-
FieldIdx, HasDataLayout, Integer, Primitive, TagEncoding, VariantIdx, Variants,
14-
};
12+
use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
1513

1614
use super::type_map::{DINodeCreationResult, UniqueTypeId};
1715
use super::{size_and_align_of, SmallVec};
@@ -39,7 +37,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
3937

4038
let enum_type_and_layout = cx.layout_of(enum_type);
4139

42-
if wants_c_like_enum_debuginfo(enum_type_and_layout) {
40+
if wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout) {
4341
return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout);
4442
}
4543

@@ -74,7 +72,7 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
7472
di_node: build_enumeration_type_di_node(
7573
cx,
7674
&compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
77-
tag_base_type(cx, enum_type_and_layout),
75+
tag_base_type(cx.tcx, enum_type_and_layout),
7876
enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
7977
let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
8078
(name, discr.val)
@@ -85,48 +83,6 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
8583
}
8684
}
8785

88-
/// Extract the type with which we want to describe the tag of the given enum or coroutine.
89-
fn tag_base_type<'ll, 'tcx>(
90-
cx: &CodegenCx<'ll, 'tcx>,
91-
enum_type_and_layout: TyAndLayout<'tcx>,
92-
) -> Ty<'tcx> {
93-
assert!(match enum_type_and_layout.ty.kind() {
94-
ty::Coroutine(..) => true,
95-
ty::Adt(adt_def, _) => adt_def.is_enum(),
96-
_ => false,
97-
});
98-
99-
match enum_type_and_layout.layout.variants() {
100-
// A single-variant enum has no discriminant.
101-
Variants::Single { .. } => {
102-
bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
103-
}
104-
105-
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
106-
// Niche tags are always normalized to unsized integers of the correct size.
107-
match tag.primitive() {
108-
Primitive::Int(t, _) => t,
109-
Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
110-
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
111-
Primitive::Pointer(_) => {
112-
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be
113-
// a RawPtr. CodeView doesn't know what to do with enums whose base type is a
114-
// pointer so we fix this up to just be `usize`.
115-
// DWARF might be able to deal with this but with an integer type we are on
116-
// the safe side there too.
117-
cx.data_layout().ptr_sized_integer()
118-
}
119-
}
120-
.to_ty(cx.tcx, false)
121-
}
122-
123-
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
124-
// Direct tags preserve the sign.
125-
tag.primitive().to_ty(cx.tcx)
126-
}
127-
}
128-
}
129-
13086
/// Build a DW_TAG_enumeration_type debuginfo node, with the given base type and variants.
13187
/// This is a helper function and does not register anything in the type map by itself.
13288
///

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::borrow::Cow;
22

33
use libc::c_uint;
44
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
5-
use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
5+
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
66
use rustc_codegen_ssa::traits::ConstMethods;
77
use rustc_middle::bug;
88
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
@@ -11,7 +11,6 @@ use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants};
1111
use smallvec::smallvec;
1212

1313
use crate::common::CodegenCx;
14-
use crate::debuginfo::metadata::enums::tag_base_type;
1514
use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
1615
use crate::debuginfo::metadata::{
1716
file_metadata, size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags,
@@ -54,7 +53,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
5453

5554
let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
5655

57-
assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
56+
assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
5857

5958
type_map::build_type_with_children(
6059
cx,
@@ -131,7 +130,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
131130
let containing_scope = get_namespace_for_item(cx, coroutine_def_id);
132131
let coroutine_type_and_layout = cx.layout_of(coroutine_type);
133132

134-
assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
133+
assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));
135134

136135
let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
137136

@@ -321,7 +320,7 @@ fn build_discr_member_di_node<'ll, 'tcx>(
321320
&Variants::Single { .. } => None,
322321

323322
&Variants::Multiple { tag_field, .. } => {
324-
let tag_base_type = tag_base_type(cx, enum_or_coroutine_type_and_layout);
323+
let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
325324
let (size, align) = cx.size_and_align_of(tag_base_type);
326325

327326
unsafe {

compiler/rustc_codegen_ssa/src/debuginfo/mod.rs

+65-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use rustc_middle::ty::layout::TyAndLayout;
2-
use rustc_middle::ty::{self};
3-
use rustc_target::abi::Size;
1+
use rustc_middle::bug;
2+
use rustc_middle::ty::layout::{IntegerExt, PrimitiveExt, TyAndLayout};
3+
use rustc_middle::ty::{self, Ty, TyCtxt};
4+
use rustc_target::abi::{Integer, Primitive, Size, TagEncoding, Variants};
45

56
// FIXME(eddyb) find a place for this (or a way to replace it).
67
pub mod type_names;
@@ -11,13 +12,25 @@ pub mod type_names;
1112
/// NOTE: This is somewhat inconsistent right now: For empty enums and enums with a single
1213
/// fieldless variant, we generate DW_TAG_struct_type, although a
1314
/// DW_TAG_enumeration_type would be a better fit.
14-
pub fn wants_c_like_enum_debuginfo(enum_type_and_layout: TyAndLayout<'_>) -> bool {
15+
pub fn wants_c_like_enum_debuginfo<'tcx>(
16+
tcx: TyCtxt<'tcx>,
17+
enum_type_and_layout: TyAndLayout<'tcx>,
18+
) -> bool {
1519
match enum_type_and_layout.ty.kind() {
1620
ty::Adt(adt_def, _) => {
1721
if !adt_def.is_enum() {
1822
return false;
1923
}
2024

25+
if type_names::cpp_like_debuginfo(tcx)
26+
&& tag_base_type_opt(tcx, enum_type_and_layout)
27+
.map(|ty| ty.primitive_size(tcx).bits())
28+
== Some(128)
29+
{
30+
// C++-like debuginfo never uses the C-like representation for 128-bit enums.
31+
return false;
32+
}
33+
2134
match adt_def.variants().len() {
2235
0 => false,
2336
1 => {
@@ -33,3 +46,51 @@ pub fn wants_c_like_enum_debuginfo(enum_type_and_layout: TyAndLayout<'_>) -> boo
3346
_ => false,
3447
}
3548
}
49+
50+
/// Extract the type with which we want to describe the tag of the given enum or coroutine.
51+
pub fn tag_base_type<'tcx>(tcx: TyCtxt<'tcx>, enum_type_and_layout: TyAndLayout<'tcx>) -> Ty<'tcx> {
52+
tag_base_type_opt(tcx, enum_type_and_layout).unwrap_or_else(|| {
53+
bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
54+
})
55+
}
56+
57+
pub fn tag_base_type_opt<'tcx>(
58+
tcx: TyCtxt<'tcx>,
59+
enum_type_and_layout: TyAndLayout<'tcx>,
60+
) -> Option<Ty<'tcx>> {
61+
assert!(match enum_type_and_layout.ty.kind() {
62+
ty::Coroutine(..) => true,
63+
ty::Adt(adt_def, _) => adt_def.is_enum(),
64+
_ => false,
65+
});
66+
67+
match enum_type_and_layout.layout.variants() {
68+
// A single-variant enum has no discriminant.
69+
Variants::Single { .. } => None,
70+
71+
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
72+
// Niche tags are always normalized to unsized integers of the correct size.
73+
Some(
74+
match tag.primitive() {
75+
Primitive::Int(t, _) => t,
76+
Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
77+
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
78+
Primitive::Pointer(_) => {
79+
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be
80+
// a RawPtr. CodeView doesn't know what to do with enums whose base type is a
81+
// pointer so we fix this up to just be `usize`.
82+
// DWARF might be able to deal with this but with an integer type we are on
83+
// the safe side there too.
84+
tcx.data_layout.ptr_sized_integer()
85+
}
86+
}
87+
.to_ty(tcx, false),
88+
)
89+
}
90+
91+
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
92+
// Direct tags preserve the sign.
93+
Some(tag.primitive().to_ty(tcx))
94+
}
95+
}
96+
}

compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn push_debuginfo_type_name<'tcx>(
8585
let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() {
8686
match tcx.layout_of(ParamEnv::reveal_all().and(t)) {
8787
Ok(layout) => {
88-
if !wants_c_like_enum_debuginfo(layout) {
88+
if !wants_c_like_enum_debuginfo(tcx, layout) {
8989
Some(layout)
9090
} else {
9191
// This is a C-like enum so we don't want to use the fallback encoding
@@ -106,6 +106,7 @@ fn push_debuginfo_type_name<'tcx>(
106106

107107
if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
108108
msvc_enum_fallback(
109+
tcx,
109110
ty_and_layout,
110111
&|output, visited| {
111112
push_item_name(tcx, def.did(), true, output);
@@ -421,6 +422,7 @@ fn push_debuginfo_type_name<'tcx>(
421422
if cpp_like_debuginfo && t.is_coroutine() {
422423
let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
423424
msvc_enum_fallback(
425+
tcx,
424426
ty_and_layout,
425427
&|output, visited| {
426428
push_closure_or_coroutine_name(tcx, def_id, args, true, output, visited);
@@ -455,12 +457,13 @@ fn push_debuginfo_type_name<'tcx>(
455457
// debugger. For more information, look in
456458
// rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs.
457459
fn msvc_enum_fallback<'tcx>(
460+
tcx: TyCtxt<'tcx>,
458461
ty_and_layout: TyAndLayout<'tcx>,
459462
push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
460463
output: &mut String,
461464
visited: &mut FxHashSet<Ty<'tcx>>,
462465
) {
463-
assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
466+
assert!(!wants_c_like_enum_debuginfo(tcx, ty_and_layout));
464467
output.push_str("enum2$<");
465468
push_inner(output, visited);
466469
push_close_angle_bracket(true, output);

tests/debuginfo/msvc-pretty-enums.rs

+50
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,30 @@
206206
// cdb-command: dx -r2 arbitrary_discr2,d
207207
// cdb-check: arbitrary_discr2,d : Def [Type: enum2$<msvc_pretty_enums::ArbitraryDiscr>]
208208
// cdb-check: [+0x[...]] __0 : 5678 [Type: unsigned int]
209+
//
210+
// cdb-command: dx c_style_u128_a
211+
// cdb-check: c_style_u128_a : A [Type: enum2$<msvc_pretty_enums::CStyleU128>]
212+
//
213+
// cdb-command: dx c_style_u128_b
214+
// cdb-check: c_style_u128_b : B [Type: enum2$<msvc_pretty_enums::CStyleU128>]
215+
//
216+
// cdb-command: dx c_style_u128_c
217+
// cdb-check: c_style_u128_c : C [Type: enum2$<msvc_pretty_enums::CStyleU128>]
218+
//
219+
// cdb-command: dx c_style_u128_d
220+
// cdb-check: c_style_u128_d : D [Type: enum2$<msvc_pretty_enums::CStyleU128>]
221+
//
222+
// cdb-command: dx c_style_i128_a
223+
// cdb-check: c_style_i128_a : A [Type: enum2$<msvc_pretty_enums::CStyleI128>]
224+
//
225+
// cdb-command: dx c_style_i128_b
226+
// cdb-check: c_style_i128_b : B [Type: enum2$<msvc_pretty_enums::CStyleI128>]
227+
//
228+
// cdb-command: dx c_style_i128_c
229+
// cdb-check: c_style_i128_c : C [Type: enum2$<msvc_pretty_enums::CStyleI128>]
230+
//
231+
// cdb-command: dx c_style_i128_d
232+
// cdb-check: c_style_i128_d : D [Type: enum2$<msvc_pretty_enums::CStyleI128>]
209233
#![feature(rustc_attrs)]
210234
#![feature(repr128)]
211235
#![feature(arbitrary_enum_discriminant)]
@@ -270,6 +294,22 @@ enum ArbitraryDiscr {
270294
Def(u32) = 5000_000,
271295
}
272296

297+
#[repr(u128)]
298+
pub enum CStyleU128 {
299+
A = 0_u128,
300+
B = 1_u128,
301+
C = u64::MAX as u128 + 1,
302+
D = u128::MAX,
303+
}
304+
305+
#[repr(i128)]
306+
pub enum CStyleI128 {
307+
A = 0_i128,
308+
B = -1_i128,
309+
C = i128::MIN,
310+
D = i128::MAX,
311+
}
312+
273313
fn main() {
274314
let a = Some(CStyleEnum::Low);
275315
let b = Option::<CStyleEnum>::None;
@@ -313,6 +353,16 @@ fn main() {
313353
let arbitrary_discr1 = ArbitraryDiscr::Abc(1234);
314354
let arbitrary_discr2 = ArbitraryDiscr::Def(5678);
315355

356+
let c_style_u128_a = CStyleU128::A;
357+
let c_style_u128_b = CStyleU128::B;
358+
let c_style_u128_c = CStyleU128::C;
359+
let c_style_u128_d = CStyleU128::D;
360+
361+
let c_style_i128_a = CStyleI128::A;
362+
let c_style_i128_b = CStyleI128::B;
363+
let c_style_i128_c = CStyleI128::C;
364+
let c_style_i128_d = CStyleI128::D;
365+
316366
zzz(); // #break
317367
}
318368

0 commit comments

Comments
 (0)