Skip to content

Commit 98dabb6

Browse files
committed
Use the enum2$ Natvis visualiser for repr128 C-style enums
1 parent 92c6c03 commit 98dabb6

File tree

6 files changed

+132
-61
lines changed

6 files changed

+132
-61
lines changed

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

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

33
use libc::c_uint;
44
use rustc_codegen_ssa::{
5-
debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo},
5+
debuginfo::{
6+
tag_base_type, type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo,
7+
},
68
traits::ConstMethods,
79
};
810

@@ -23,7 +25,7 @@ use crate::{
2325
debuginfo::{
2426
metadata::{
2527
build_field_di_node,
26-
enums::{tag_base_type, DiscrResult},
28+
enums::DiscrResult,
2729
file_metadata, size_and_align_of, type_di_node,
2830
type_map::{self, Stub, UniqueTypeId},
2931
unknown_file_metadata, visibility_di_flags, DINodeCreationResult, SmallVec,
@@ -204,7 +206,10 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
204206
let enum_type_and_layout = cx.layout_of(enum_type);
205207
let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
206208

207-
debug_assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
209+
debug_assert!(
210+
!wants_c_like_enum_debuginfo(enum_type_and_layout)
211+
|| tag_base_type(cx.tcx, enum_type_and_layout).primitive_size(cx.tcx).bits() == 128
212+
);
208213

209214
type_map::build_type_with_children(
210215
cx,
@@ -395,7 +400,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
395400
tag_field: usize,
396401
untagged_variant_index: Option<VariantIdx>,
397402
) -> SmallVec<&'ll DIType> {
398-
let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
403+
let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
399404

400405
let variant_names_type_di_node = build_variant_names_type_di_node(
401406
cx,
@@ -690,7 +695,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
690695
let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);
691696
let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len();
692697

693-
let tag_base_type = tag_base_type(cx, coroutine_type_and_layout);
698+
let tag_base_type = tag_base_type(cx.tcx, coroutine_type_and_layout);
694699

695700
let variant_names_type_di_node = build_variant_names_type_di_node(
696701
cx,
@@ -817,7 +822,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
817822

818823
debug_assert_eq!(
819824
cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
820-
cx.size_and_align_of(super::tag_base_type(cx, enum_type_and_layout))
825+
cx.size_and_align_of(self::tag_base_type(cx.tcx, enum_type_and_layout))
821826
);
822827

823828
// ... 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

+10-47
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_codegen_ssa::debuginfo::{
2+
tag_base_type,
23
type_names::{compute_debuginfo_type_name, cpp_like_debuginfo},
34
wants_c_like_enum_debuginfo,
45
};
@@ -9,14 +10,12 @@ use rustc_middle::{
910
mir::CoroutineLayout,
1011
ty::{
1112
self,
12-
layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout},
13+
layout::{LayoutOf, TyAndLayout},
1314
AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef,
1415
},
1516
};
1617
use rustc_span::Symbol;
17-
use rustc_target::abi::{
18-
FieldIdx, HasDataLayout, Integer, Primitive, TagEncoding, VariantIdx, Variants,
19-
};
18+
use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
2019
use std::borrow::Cow;
2120

2221
use crate::{
@@ -55,6 +54,12 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
5554

5655
let enum_type_and_layout = cx.layout_of(enum_type);
5756

57+
if cpp_like_debuginfo(cx.tcx)
58+
&& tag_base_type(cx.tcx, enum_type_and_layout).primitive_size(cx.tcx).bits() == 128
59+
{
60+
return cpp_like::build_enum_type_di_node(cx, unique_type_id);
61+
}
62+
5863
if wants_c_like_enum_debuginfo(enum_type_and_layout) {
5964
return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout);
6065
}
@@ -90,7 +95,7 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
9095
di_node: build_enumeration_type_di_node(
9196
cx,
9297
&compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
93-
tag_base_type(cx, enum_type_and_layout),
98+
tag_base_type(cx.tcx, enum_type_and_layout),
9499
enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
95100
let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
96101
(name, discr.val)
@@ -101,48 +106,6 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
101106
}
102107
}
103108

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

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use crate::{
44
common::CodegenCx,
55
debuginfo::{
66
metadata::{
7-
enums::tag_base_type,
87
file_metadata, size_and_align_of, type_di_node,
98
type_map::{self, Stub, StubInfo, UniqueTypeId},
109
unknown_file_metadata, visibility_di_flags, DINodeCreationResult, SmallVec,
@@ -19,7 +18,9 @@ use crate::{
1918
};
2019
use libc::c_uint;
2120
use rustc_codegen_ssa::{
22-
debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo},
21+
debuginfo::{
22+
tag_base_type, type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo,
23+
},
2324
traits::ConstMethods,
2425
};
2526
use rustc_middle::{
@@ -332,7 +333,7 @@ fn build_discr_member_di_node<'ll, 'tcx>(
332333
&Variants::Single { .. } => None,
333334

334335
&Variants::Multiple { tag_field, .. } => {
335-
let tag_base_type = tag_base_type(cx, enum_or_coroutine_type_and_layout);
336+
let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
336337
let (size, align) = cx.size_and_align_of(tag_base_type);
337338

338339
unsafe {

compiler/rustc_codegen_ssa/src/debuginfo/mod.rs

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

49
// FIXME(eddyb) find a place for this (or a way to replace it).
510
pub mod type_names;
@@ -32,3 +37,42 @@ pub fn wants_c_like_enum_debuginfo(enum_type_and_layout: TyAndLayout<'_>) -> boo
3237
_ => false,
3338
}
3439
}
40+
41+
/// Extract the type with which we want to describe the tag of the given enum or coroutine.
42+
pub fn tag_base_type<'tcx>(tcx: TyCtxt<'tcx>, enum_type_and_layout: TyAndLayout<'tcx>) -> Ty<'tcx> {
43+
debug_assert!(match enum_type_and_layout.ty.kind() {
44+
ty::Coroutine(..) => true,
45+
ty::Adt(adt_def, _) => adt_def.is_enum(),
46+
_ => false,
47+
});
48+
49+
match enum_type_and_layout.layout.variants() {
50+
// A single-variant enum has no discriminant.
51+
Variants::Single { .. } => {
52+
bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
53+
}
54+
55+
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
56+
// Niche tags are always normalized to unsized integers of the correct size.
57+
match tag.primitive() {
58+
Primitive::Int(t, _) => t,
59+
Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
60+
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
61+
Primitive::Pointer(_) => {
62+
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be
63+
// a RawPtr. CodeView doesn't know what to do with enums whose base type is a
64+
// pointer so we fix this up to just be `usize`.
65+
// DWARF might be able to deal with this but with an integer type we are on
66+
// the safe side there too.
67+
tcx.data_layout.ptr_sized_integer()
68+
}
69+
}
70+
.to_ty(tcx, false)
71+
}
72+
73+
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
74+
// Direct tags preserve the sign.
75+
tag.primitive().to_ty(tcx)
76+
}
77+
}
78+
}

compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use smallvec::SmallVec;
2626

2727
use std::fmt::Write;
2828

29-
use crate::debuginfo::wants_c_like_enum_debuginfo;
29+
use crate::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
3030

3131
/// Compute the name of the type as it should be stored in debuginfo. Does not do
3232
/// any caching, i.e., calling the function twice with the same type will also do
@@ -84,7 +84,9 @@ fn push_debuginfo_type_name<'tcx>(
8484
let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() {
8585
match tcx.layout_of(ParamEnv::reveal_all().and(t)) {
8686
Ok(layout) => {
87-
if !wants_c_like_enum_debuginfo(layout) {
87+
if !wants_c_like_enum_debuginfo(layout)
88+
|| tag_base_type(tcx, layout).primitive_size(tcx).bits() == 128
89+
{
8890
Some(layout)
8991
} else {
9092
// This is a C-like enum so we don't want to use the fallback encoding
@@ -105,6 +107,7 @@ fn push_debuginfo_type_name<'tcx>(
105107

106108
if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
107109
msvc_enum_fallback(
110+
tcx,
108111
ty_and_layout,
109112
&|output, visited| {
110113
push_item_name(tcx, def.did(), true, output);
@@ -420,6 +423,7 @@ fn push_debuginfo_type_name<'tcx>(
420423
if cpp_like_debuginfo && t.is_coroutine() {
421424
let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
422425
msvc_enum_fallback(
426+
tcx,
423427
ty_and_layout,
424428
&|output, visited| {
425429
push_closure_or_coroutine_name(tcx, def_id, args, true, output, visited);
@@ -454,12 +458,16 @@ fn push_debuginfo_type_name<'tcx>(
454458
// debugger. For more information, look in
455459
// rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs.
456460
fn msvc_enum_fallback<'tcx>(
461+
tcx: TyCtxt<'tcx>,
457462
ty_and_layout: TyAndLayout<'tcx>,
458463
push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
459464
output: &mut String,
460465
visited: &mut FxHashSet<Ty<'tcx>>,
461466
) {
462-
debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
467+
debug_assert!(
468+
!wants_c_like_enum_debuginfo(ty_and_layout)
469+
|| super::tag_base_type(tcx, ty_and_layout).primitive_size(tcx).bits() == 128
470+
);
463471
output.push_str("enum2$<");
464472
push_inner(output, visited);
465473
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+
U128A = 0_u128,
300+
U128B = 1_u128,
301+
U128C = u64::MAX as u128 + 1,
302+
U128D = u128::MAX,
303+
}
304+
305+
#[repr(i128)]
306+
pub enum CStyleI128 {
307+
I128A = 0_i128,
308+
I128B = -1_i128,
309+
I128C = i128::MIN,
310+
I128D = 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)