Skip to content

Commit

Permalink
Auto merge of rust-lang#128037 - beetrees:repr128-c-style-use-natvis,…
Browse files Browse the repository at this point in the history
… r=<try>

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
  • Loading branch information
bors committed Jul 25, 2024
2 parents aa877bc + 16cb907 commit 9d1bbd9
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::borrow::Cow;

use libc::c_uint;
use rustc_codegen_ssa::{
debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo},
debuginfo::{
tag_base_type, type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo,
},
traits::ConstMethods,
};

Expand All @@ -23,7 +25,7 @@ use crate::{
debuginfo::{
metadata::{
build_field_di_node,
enums::{tag_base_type, DiscrResult},
enums::DiscrResult,
file_metadata, size_and_align_of, type_di_node,
type_map::{self, Stub, UniqueTypeId},
unknown_file_metadata, visibility_di_flags, DINodeCreationResult, SmallVec,
Expand Down Expand Up @@ -204,7 +206,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 @@ -279,7 +281,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 @@ -395,7 +397,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 @@ -690,7 +692,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 @@ -817,7 +819,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
53 changes: 5 additions & 48 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rustc_codegen_ssa::debuginfo::{
tag_base_type,
type_names::{compute_debuginfo_type_name, cpp_like_debuginfo},
wants_c_like_enum_debuginfo,
};
Expand All @@ -9,14 +10,12 @@ use rustc_middle::{
mir::CoroutineLayout,
ty::{
self,
layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout},
layout::{LayoutOf, TyAndLayout},
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 std::borrow::Cow;

use crate::{
Expand Down Expand Up @@ -55,7 +54,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 @@ -90,7 +89,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 @@ -101,48 +100,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 @@ -4,7 +4,6 @@ use crate::{
common::CodegenCx,
debuginfo::{
metadata::{
enums::tag_base_type,
file_metadata, size_and_align_of, type_di_node,
type_map::{self, Stub, StubInfo, UniqueTypeId},
unknown_file_metadata, visibility_di_flags, DINodeCreationResult, SmallVec,
Expand All @@ -19,7 +18,9 @@ use crate::{
};
use libc::c_uint;
use rustc_codegen_ssa::{
debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo},
debuginfo::{
tag_base_type, type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo,
},
traits::ConstMethods,
};
use rustc_middle::{
Expand Down Expand Up @@ -65,7 +66,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 @@ -142,7 +143,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 @@ -332,7 +333,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
71 changes: 68 additions & 3 deletions compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use rustc_middle::ty::{self, layout::TyAndLayout};
use rustc_target::abi::Size;
use rustc_middle::bug;
use rustc_middle::ty::{
self,
layout::{IntegerExt, PrimitiveExt, TyAndLayout},
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 @@ -10,13 +15,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 @@ -32,3 +49,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 @@ -84,7 +84,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 @@ -105,6 +105,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 @@ -420,6 +421,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 @@ -454,12 +456,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
Loading

0 comments on commit 9d1bbd9

Please sign in to comment.