diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 12f98eef97d43..cbd26bc37ab20 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -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, }; @@ -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, @@ -204,7 +206,10 @@ 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); - debug_assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout)); + debug_assert!( + !wants_c_like_enum_debuginfo(enum_type_and_layout) + || tag_base_type(cx.tcx, enum_type_and_layout).primitive_size(cx.tcx).bits() == 128 + ); type_map::build_type_with_children( cx, @@ -395,7 +400,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>( tag_field: usize, untagged_variant_index: Option, ) -> 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, @@ -690,7 +695,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, @@ -817,7 +822,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>( debug_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 diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 2b00bb14593e4..e5b3026714bb6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -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, }; @@ -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::{ @@ -55,6 +54,12 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( let enum_type_and_layout = cx.layout_of(enum_type); + if cpp_like_debuginfo(cx.tcx) + && tag_base_type(cx.tcx, enum_type_and_layout).primitive_size(cx.tcx).bits() == 128 + { + return cpp_like::build_enum_type_di_node(cx, unique_type_id); + } + if wants_c_like_enum_debuginfo(enum_type_and_layout) { return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout); } @@ -90,7 +95,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) @@ -101,48 +106,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> { - debug_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. /// diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 115d5187eafa8..9d5bbbb5472f3 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -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, @@ -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::{ @@ -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 { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs index 60e9b40e8fb40..d6d7bcef0f1e5 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs @@ -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; @@ -32,3 +37,42 @@ 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> { + debug_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. + tcx.data_layout.ptr_sized_integer() + } + } + .to_ty(tcx, false) + } + + Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => { + // Direct tags preserve the sign. + tag.primitive().to_ty(tcx) + } + } +} diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index c4e5c8582404b..b75d079626dab 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -26,7 +26,7 @@ use smallvec::SmallVec; use std::fmt::Write; -use crate::debuginfo::wants_c_like_enum_debuginfo; +use crate::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo}; /// Compute the name of the type as it should be stored in debuginfo. Does not do /// 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>( 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(layout) + || tag_base_type(tcx, layout).primitive_size(tcx).bits() == 128 + { Some(layout) } else { // 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>( 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); @@ -420,6 +423,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); @@ -454,12 +458,16 @@ 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>), output: &mut String, visited: &mut FxHashSet>, ) { - debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout)); + debug_assert!( + !wants_c_like_enum_debuginfo(ty_and_layout) + || super::tag_base_type(tcx, ty_and_layout).primitive_size(tcx).bits() == 128 + ); output.push_str("enum2$<"); push_inner(output, visited); push_close_angle_bracket(true, output); diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs index a6032cc864235..6cef47f920443 100644 --- a/tests/debuginfo/msvc-pretty-enums.rs +++ b/tests/debuginfo/msvc-pretty-enums.rs @@ -206,6 +206,30 @@ // cdb-command: dx -r2 arbitrary_discr2,d // cdb-check: arbitrary_discr2,d : Def [Type: enum2$] // cdb-check: [+0x[...]] __0 : 5678 [Type: unsigned int] +// +// cdb-command: dx c_style_u128_a +// cdb-check: c_style_u128_a : A [Type: enum2$] +// +// cdb-command: dx c_style_u128_b +// cdb-check: c_style_u128_b : B [Type: enum2$] +// +// cdb-command: dx c_style_u128_c +// cdb-check: c_style_u128_c : C [Type: enum2$] +// +// cdb-command: dx c_style_u128_d +// cdb-check: c_style_u128_d : D [Type: enum2$] +// +// cdb-command: dx c_style_i128_a +// cdb-check: c_style_i128_a : A [Type: enum2$] +// +// cdb-command: dx c_style_i128_b +// cdb-check: c_style_i128_b : B [Type: enum2$] +// +// cdb-command: dx c_style_i128_c +// cdb-check: c_style_i128_c : C [Type: enum2$] +// +// cdb-command: dx c_style_i128_d +// cdb-check: c_style_i128_d : D [Type: enum2$] #![feature(rustc_attrs)] #![feature(repr128)] #![feature(arbitrary_enum_discriminant)] @@ -270,6 +294,22 @@ enum ArbitraryDiscr { Def(u32) = 5000_000, } +#[repr(u128)] +pub enum CStyleU128 { + U128A = 0_u128, + U128B = 1_u128, + U128C = u64::MAX as u128 + 1, + U128D = u128::MAX, +} + +#[repr(i128)] +pub enum CStyleI128 { + I128A = 0_i128, + I128B = -1_i128, + I128C = i128::MIN, + I128D = i128::MAX, +} + fn main() { let a = Some(CStyleEnum::Low); let b = Option::::None; @@ -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 }