Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the enum2$ Natvis visualiser for repr128 C-style enums #128037

Merged
merged 1 commit into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::borrow::Cow;

use libc::c_uint;
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_codegen_ssa::traits::ConstMethods;
use rustc_index::IndexVec;
use rustc_middle::bug;
Expand All @@ -12,7 +12,7 @@ use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};
use smallvec::smallvec;

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

assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));

type_map::build_type_with_children(
cx,
Expand Down Expand Up @@ -265,7 +265,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
let coroutine_type_and_layout = cx.layout_of(coroutine_type);
let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);

assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));

type_map::build_type_with_children(
cx,
Expand Down Expand Up @@ -381,7 +381,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
tag_field: usize,
untagged_variant_index: Option<VariantIdx>,
) -> SmallVec<&'ll DIType> {
let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);

let variant_names_type_di_node = build_variant_names_type_di_node(
cx,
Expand Down Expand Up @@ -676,7 +676,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);
let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len();

let tag_base_type = tag_base_type(cx, coroutine_type_and_layout);
let tag_base_type = tag_base_type(cx.tcx, coroutine_type_and_layout);

let variant_names_type_di_node = build_variant_names_type_di_node(
cx,
Expand Down Expand Up @@ -803,7 +803,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(

assert_eq!(
cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
cx.size_and_align_of(super::tag_base_type(cx, enum_type_and_layout))
cx.size_and_align_of(self::tag_base_type(cx.tcx, enum_type_and_layout))
);

// ... and a field for the tag. If the tag is 128 bits wide, this will actually
Expand Down
54 changes: 5 additions & 49 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
use std::borrow::Cow;

use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_like_debuginfo};
use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_hir::def::CtorKind;
use rustc_index::IndexSlice;
use rustc_middle::bug;
use rustc_middle::mir::CoroutineLayout;
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef};
use rustc_span::Symbol;
use rustc_target::abi::{
FieldIdx, HasDataLayout, Integer, Primitive, TagEncoding, VariantIdx, Variants,
};
use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants};

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

let enum_type_and_layout = cx.layout_of(enum_type);

if wants_c_like_enum_debuginfo(enum_type_and_layout) {
if wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout) {
return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout);
}

Expand Down Expand Up @@ -74,7 +72,7 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
di_node: build_enumeration_type_di_node(
cx,
&compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
tag_base_type(cx, enum_type_and_layout),
tag_base_type(cx.tcx, enum_type_and_layout),
enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
(name, discr.val)
Expand All @@ -85,48 +83,6 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
}
}

/// Extract the type with which we want to describe the tag of the given enum or coroutine.
fn tag_base_type<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
enum_type_and_layout: TyAndLayout<'tcx>,
) -> Ty<'tcx> {
assert!(match enum_type_and_layout.ty.kind() {
ty::Coroutine(..) => true,
ty::Adt(adt_def, _) => adt_def.is_enum(),
_ => false,
});

match enum_type_and_layout.layout.variants() {
// A single-variant enum has no discriminant.
Variants::Single { .. } => {
bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
}

Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
// Niche tags are always normalized to unsized integers of the correct size.
match tag.primitive() {
Primitive::Int(t, _) => t,
Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => {
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be
// a RawPtr. CodeView doesn't know what to do with enums whose base type is a
// pointer so we fix this up to just be `usize`.
// DWARF might be able to deal with this but with an integer type we are on
// the safe side there too.
cx.data_layout().ptr_sized_integer()
}
}
.to_ty(cx.tcx, false)
}

Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
// Direct tags preserve the sign.
tag.primitive().to_ty(cx.tcx)
}
}
}

/// Build a DW_TAG_enumeration_type debuginfo node, with the given base type and variants.
/// This is a helper function and does not register anything in the type map by itself.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::borrow::Cow;

use libc::c_uint;
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_codegen_ssa::traits::ConstMethods;
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
Expand All @@ -11,7 +11,6 @@ use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants};
use smallvec::smallvec;

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

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

assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));

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

assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));

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

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

&Variants::Multiple { tag_field, .. } => {
let tag_base_type = tag_base_type(cx, enum_or_coroutine_type_and_layout);
let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
let (size, align) = cx.size_and_align_of(tag_base_type);

unsafe {
Expand Down
69 changes: 65 additions & 4 deletions compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self};
use rustc_target::abi::Size;
use rustc_middle::bug;
use rustc_middle::ty::layout::{IntegerExt, PrimitiveExt, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_target::abi::{Integer, Primitive, Size, TagEncoding, Variants};

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

if type_names::cpp_like_debuginfo(tcx)
&& tag_base_type_opt(tcx, enum_type_and_layout)
.map(|ty| ty.primitive_size(tcx).bits())
== Some(128)
{
// C++-like debuginfo never uses the C-like representation for 128-bit enums.
return false;
}

match adt_def.variants().len() {
0 => false,
1 => {
Expand All @@ -33,3 +46,51 @@ pub fn wants_c_like_enum_debuginfo(enum_type_and_layout: TyAndLayout<'_>) -> boo
_ => false,
}
}

/// Extract the type with which we want to describe the tag of the given enum or coroutine.
pub fn tag_base_type<'tcx>(tcx: TyCtxt<'tcx>, enum_type_and_layout: TyAndLayout<'tcx>) -> Ty<'tcx> {
tag_base_type_opt(tcx, enum_type_and_layout).unwrap_or_else(|| {
bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
})
}

pub fn tag_base_type_opt<'tcx>(
tcx: TyCtxt<'tcx>,
enum_type_and_layout: TyAndLayout<'tcx>,
) -> Option<Ty<'tcx>> {
assert!(match enum_type_and_layout.ty.kind() {
ty::Coroutine(..) => true,
ty::Adt(adt_def, _) => adt_def.is_enum(),
_ => false,
});

match enum_type_and_layout.layout.variants() {
// A single-variant enum has no discriminant.
Variants::Single { .. } => None,

Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
// Niche tags are always normalized to unsized integers of the correct size.
Some(
match tag.primitive() {
Primitive::Int(t, _) => t,
Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => {
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be
// a RawPtr. CodeView doesn't know what to do with enums whose base type is a
// pointer so we fix this up to just be `usize`.
// DWARF might be able to deal with this but with an integer type we are on
// the safe side there too.
tcx.data_layout.ptr_sized_integer()
}
}
.to_ty(tcx, false),
)
}

Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
// Direct tags preserve the sign.
Some(tag.primitive().to_ty(tcx))
}
}
}
7 changes: 5 additions & 2 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn push_debuginfo_type_name<'tcx>(
let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() {
match tcx.layout_of(ParamEnv::reveal_all().and(t)) {
Ok(layout) => {
if !wants_c_like_enum_debuginfo(layout) {
if !wants_c_like_enum_debuginfo(tcx, layout) {
Some(layout)
} else {
// This is a C-like enum so we don't want to use the fallback encoding
Expand All @@ -106,6 +106,7 @@ fn push_debuginfo_type_name<'tcx>(

if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
msvc_enum_fallback(
tcx,
ty_and_layout,
&|output, visited| {
push_item_name(tcx, def.did(), true, output);
Expand Down Expand Up @@ -421,6 +422,7 @@ fn push_debuginfo_type_name<'tcx>(
if cpp_like_debuginfo && t.is_coroutine() {
let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
msvc_enum_fallback(
tcx,
ty_and_layout,
&|output, visited| {
push_closure_or_coroutine_name(tcx, def_id, args, true, output, visited);
Expand Down Expand Up @@ -455,12 +457,13 @@ fn push_debuginfo_type_name<'tcx>(
// debugger. For more information, look in
// rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs.
fn msvc_enum_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
ty_and_layout: TyAndLayout<'tcx>,
push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
output: &mut String,
visited: &mut FxHashSet<Ty<'tcx>>,
) {
assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
assert!(!wants_c_like_enum_debuginfo(tcx, ty_and_layout));
output.push_str("enum2$<");
push_inner(output, visited);
push_close_angle_bracket(true, output);
Expand Down
50 changes: 50 additions & 0 deletions tests/debuginfo/msvc-pretty-enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,30 @@
// cdb-command: dx -r2 arbitrary_discr2,d
// cdb-check: arbitrary_discr2,d : Def [Type: enum2$<msvc_pretty_enums::ArbitraryDiscr>]
// cdb-check: [+0x[...]] __0 : 5678 [Type: unsigned int]
//
// cdb-command: dx c_style_u128_a
// cdb-check: c_style_u128_a : A [Type: enum2$<msvc_pretty_enums::CStyleU128>]
//
// cdb-command: dx c_style_u128_b
// cdb-check: c_style_u128_b : B [Type: enum2$<msvc_pretty_enums::CStyleU128>]
//
// cdb-command: dx c_style_u128_c
// cdb-check: c_style_u128_c : C [Type: enum2$<msvc_pretty_enums::CStyleU128>]
//
// cdb-command: dx c_style_u128_d
// cdb-check: c_style_u128_d : D [Type: enum2$<msvc_pretty_enums::CStyleU128>]
//
// cdb-command: dx c_style_i128_a
// cdb-check: c_style_i128_a : A [Type: enum2$<msvc_pretty_enums::CStyleI128>]
//
// cdb-command: dx c_style_i128_b
// cdb-check: c_style_i128_b : B [Type: enum2$<msvc_pretty_enums::CStyleI128>]
//
// cdb-command: dx c_style_i128_c
// cdb-check: c_style_i128_c : C [Type: enum2$<msvc_pretty_enums::CStyleI128>]
//
// cdb-command: dx c_style_i128_d
// cdb-check: c_style_i128_d : D [Type: enum2$<msvc_pretty_enums::CStyleI128>]
#![feature(rustc_attrs)]
#![feature(repr128)]
#![feature(arbitrary_enum_discriminant)]
Expand Down Expand Up @@ -270,6 +294,22 @@ enum ArbitraryDiscr {
Def(u32) = 5000_000,
}

#[repr(u128)]
pub enum CStyleU128 {
A = 0_u128,
B = 1_u128,
C = u64::MAX as u128 + 1,
D = u128::MAX,
}

#[repr(i128)]
pub enum CStyleI128 {
A = 0_i128,
B = -1_i128,
C = i128::MIN,
D = i128::MAX,
}

fn main() {
let a = Some(CStyleEnum::Low);
let b = Option::<CStyleEnum>::None;
Expand Down Expand Up @@ -313,6 +353,16 @@ fn main() {
let arbitrary_discr1 = ArbitraryDiscr::Abc(1234);
let arbitrary_discr2 = ArbitraryDiscr::Def(5678);

let c_style_u128_a = CStyleU128::A;
let c_style_u128_b = CStyleU128::B;
let c_style_u128_c = CStyleU128::C;
let c_style_u128_d = CStyleU128::D;

let c_style_i128_a = CStyleI128::A;
let c_style_i128_b = CStyleI128::B;
let c_style_i128_c = CStyleI128::C;
let c_style_i128_d = CStyleI128::D;

zzz(); // #break
}

Expand Down
Loading