From 622da5d834e862112e860db1fc0404bd8604f578 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Jun 2022 17:50:27 +0200 Subject: [PATCH 01/15] debuginfo: Change C++-like encoding for enums. The updated encoding should be able to handle niche layouts where more than one variant has fields. --- .../src/debuginfo/metadata.rs | 1 + .../src/debuginfo/metadata/enums/cpp_like.rs | 660 +++++++++++++----- .../src/debuginfo/metadata/enums/mod.rs | 90 ++- .../src/debuginfo/metadata/enums/native.rs | 10 +- .../src/debuginfo/metadata/type_map.rs | 11 + compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 13 + .../src/debuginfo/type_names.rs | 52 +- compiler/rustc_index/src/vec.rs | 4 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 24 + src/etc/natvis/intrinsic.natvis | 180 +++-- src/test/debuginfo/generator-objects.rs | 5 - src/test/debuginfo/msvc-pretty-enums.rs | 142 +++- src/test/debuginfo/msvc-scalarpair-params.rs | 4 +- src/test/debuginfo/pretty-std.rs | 14 +- src/test/debuginfo/type-names.rs | 4 +- 15 files changed, 846 insertions(+), 368 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index bd84100e0e883..25a989bdf0525 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -114,6 +114,7 @@ macro_rules! return_if_di_node_created_in_meantime { } /// Extract size and alignment from a TyAndLayout. +#[inline] fn size_and_align_of<'tcx>(ty_and_layout: TyAndLayout<'tcx>) -> (Size, Align) { (ty_and_layout.size, ty_and_layout.align.abi) } 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 d6e2c8ccdf44a..55bdd29d67cde 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 @@ -1,19 +1,20 @@ use std::borrow::Cow; use libc::c_uint; -use rustc_codegen_ssa::debuginfo::{ - type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo, +use rustc_codegen_ssa::{ + debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo}, + traits::ConstMethods, }; +use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ bug, ty::{ self, layout::{LayoutOf, TyAndLayout}, - util::Discr, - AdtDef, GeneratorSubsts, + AdtDef, GeneratorSubsts, Ty, }, }; -use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants}; +use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants}; use smallvec::smallvec; use crate::{ @@ -21,9 +22,9 @@ use crate::{ debuginfo::{ metadata::{ build_field_di_node, closure_saved_names_of_captured_variables, - enums::tag_base_type, - file_metadata, generator_layout_and_saved_local_names, size_and_align_of, - type_map::{self, UniqueTypeId}, + enums::{tag_base_type, DiscrResult}, + file_metadata, generator_layout_and_saved_local_names, size_and_align_of, type_di_node, + type_map::{self, Stub, UniqueTypeId}, unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA, UNKNOWN_LINE_NUMBER, }, @@ -35,59 +36,78 @@ use crate::{ }, }; -/// In CPP-like mode, we generate a union of structs for each variant and an -/// explicit discriminant field roughly equivalent to the following C/C++ code: +// The names of the associated constants in each variant wrapper struct. +// These have to match up with the names being used in `intrinsic.natvis`. +const ASSOC_CONST_DISCR_NAME: &str = "NAME"; +const ASSOC_CONST_DISCR_EXACT: &str = "DISCR_EXACT"; +const ASSOC_CONST_DISCR_BEGIN: &str = "DISCR_BEGIN"; +const ASSOC_CONST_DISCR_END: &str = "DISCR_END"; + +const ASSOC_CONST_DISCR128_EXACT_LO: &str = "DISCR128_EXACT_LO"; +const ASSOC_CONST_DISCR128_EXACT_HI: &str = "DISCR128_EXACT_HI"; +const ASSOC_CONST_DISCR128_BEGIN_LO: &str = "DISCR128_BEGIN_LO"; +const ASSOC_CONST_DISCR128_BEGIN_HI: &str = "DISCR128_BEGIN_HI"; +const ASSOC_CONST_DISCR128_END_LO: &str = "DISCR128_END_LO"; +const ASSOC_CONST_DISCR128_END_HI: &str = "DISCR128_END_HI"; + +// The name of the tag field in the top-level union +const TAG_FIELD_NAME: &str = "tag"; +const TAG_FIELD_NAME_128_LO: &str = "tag128_lo"; +const TAG_FIELD_NAME_128_HI: &str = "tag128_hi"; + +// We assign a "virtual" discriminant value to the sole variant of +// a single-variant enum. +const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; + +/// In CPP-like mode, we generate a union with a field for each variant and an +/// explicit tag field. The field of each variant has a struct type +/// that encodes the discrimiant of the variant and it's data layout. +/// The union also has a nested enumeration type that is only used for encoding +/// variant names in an efficient way. Its enumerator values do _not_ correspond +/// to the enum's discriminant values. +/// It's roughly equivalent to the following C/C++ code: /// /// ```c /// union enum$<{fully-qualified-name}> { -/// struct {variant 0 name} { -/// +/// struct Variant0 { +/// struct {name-of-variant-0} { +/// +/// } value; +/// +/// static VariantNames NAME = {name-of-variant-0}; +/// static int_type DISCR_EXACT = {discriminant-of-variant-0}; /// } variant0; +/// /// -/// {name} discriminant; +/// +/// int_type tag; +/// +/// enum VariantNames { +/// = 0, // The numeric values are variant index, +/// = 1, // not discriminant values. +/// = 2, +/// ... +/// } /// } /// ``` /// /// As you can see, the type name is wrapped `enum$`. This way we can have a /// single NatVis rule for handling all enums. /// -/// At the LLVM IR level this looks like -/// -/// ```txt -/// DW_TAG_union_type (top-level type for enum) -/// DW_TAG_member (member for variant 1) -/// DW_TAG_member (member for variant 2) -/// DW_TAG_member (member for variant 3) -/// DW_TAG_structure_type (type of variant 1) -/// DW_TAG_structure_type (type of variant 2) -/// DW_TAG_structure_type (type of variant 3) -/// DW_TAG_enumeration_type (type of tag) -/// ``` +/// For niche-tag enums, a variant might correspond to a range of tag values. +/// In that case the variant struct has a `DISCR_BEGIN` and `DISCR_END` field +/// instead of DISCR_EXACT. /// -/// The above encoding applies for enums with a direct tag. For niche-tag we have to do things -/// differently in order to allow a NatVis visualizer to extract all the information needed: -/// We generate a union of two fields, one for the dataful variant -/// and one that just points to the discriminant (which is some field within the dataful variant). -/// We also create a DW_TAG_enumeration_type DIE that contains tag values for the non-dataful -/// variants and make the discriminant field that type. We then use NatVis to render the enum type -/// correctly in Windbg/VS. This will generate debuginfo roughly equivalent to the following C: +/// Single-variant enums don't actually have a tag field. In this case we +/// emit a static tag field (that always has the value 0) so we can use the +/// same representation (and NatVis). /// -/// ```c -/// union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> { -/// struct { -/// -/// } dataful_variant; -/// enum Discriminant$ { -/// -/// } discriminant; -/// } -/// ``` -/// -/// The NatVis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>` -/// and evaluates `this.discriminant`. If the value is between the min niche and max -/// niche, then the enum is in the dataful variant and `this.dataful_variant` is -/// rendered. Otherwise, the enum is in one of the non-dataful variants. In that -/// case, we just need to render the name of the `this.discriminant` enum. +/// For niche-layout enums it's possible to have a 128-bit tag. NatVis, VS, and +/// WinDbg (the main targets for CPP-like debuginfo at the moment) don't support +/// 128-bit integers, so all values involved get split into two 64-bit fields. +/// Instead of the `tag` field, we generate two fields `tag128_lo` and `tag128_hi`, +/// Instead of `DISCR_EXACT`, we generate `DISCR128_EXACT_LO` and `DISCR128_EXACT_HI`, +/// and so on. pub(super) fn build_enum_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, @@ -135,27 +155,28 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( ref variants, tag_field, .. - } => build_union_fields_for_direct_tag_enum( + } => build_union_fields_for_enum( cx, enum_adt_def, enum_type_and_layout, enum_type_di_node, - &mut variants.indices(), + variants.indices(), tag_field, + None, ), Variants::Multiple { tag_encoding: TagEncoding::Niche { dataful_variant, .. }, ref variants, tag_field, .. - } => build_union_fields_for_niche_tag_enum( + } => build_union_fields_for_enum( cx, enum_adt_def, enum_type_and_layout, enum_type_di_node, - dataful_variant, - &mut variants.indices(), + variants.indices(), tag_field, + Some(dataful_variant), ), } }, @@ -217,137 +238,344 @@ fn build_single_variant_union_fields<'ll, 'tcx>( let variant_layout = enum_type_and_layout.for_variant(cx, variant_index); let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node( cx, - enum_type_and_layout.ty, + enum_type_and_layout, enum_type_di_node, variant_index, enum_adt_def.variant(variant_index), variant_layout, ); - // NOTE: The field name of the union is the same as the variant name, not "variant0". - let variant_name = enum_adt_def.variant(variant_index).name.as_str(); + let tag_base_type = cx.tcx.types.u32; + let tag_base_type_di_node = type_di_node(cx, tag_base_type); + let tag_base_type_align = cx.align_of(tag_base_type); - smallvec![build_field_di_node( + let variant_names_type_di_node = build_variant_names_type_di_node( cx, enum_type_di_node, - variant_name, - // NOTE: We use the size and align of the entire type, not from variant_layout - // since the later is sometimes smaller (if it has fewer fields). - size_and_align_of(enum_type_and_layout), - Size::ZERO, - DIFlags::FlagZero, + std::iter::once(( + variant_index, + Cow::from(enum_adt_def.variant(variant_index).name.as_str()), + )), + ); + + let variant_struct_type_wrapper_di_node = build_variant_struct_wrapper_type_di_node( + cx, + enum_type_and_layout, + enum_type_di_node, + variant_index, + None, variant_struct_type_di_node, - )] + variant_names_type_di_node, + tag_base_type_di_node, + tag_base_type, + DiscrResult::NoDiscriminant, + ); + + smallvec![ + build_field_di_node( + cx, + enum_type_di_node, + &variant_union_field_name(variant_index, None), + // NOTE: We use the size and align of the entire type, not from variant_layout + // since the later is sometimes smaller (if it has fewer fields). + size_and_align_of(enum_type_and_layout), + Size::ZERO, + DIFlags::FlagZero, + variant_struct_type_wrapper_di_node, + ), + unsafe { + llvm::LLVMRustDIBuilderCreateStaticMemberType( + DIB(cx), + enum_type_di_node, + TAG_FIELD_NAME.as_ptr().cast(), + TAG_FIELD_NAME.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + variant_names_type_di_node, + DIFlags::FlagArtificial, + Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)), + tag_base_type_align.bits() as u32, + ) + } + ] } -fn build_union_fields_for_direct_tag_enum<'ll, 'tcx>( +fn build_union_fields_for_enum<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, enum_adt_def: AdtDef<'tcx>, enum_type_and_layout: TyAndLayout<'tcx>, enum_type_di_node: &'ll DIType, - variant_indices: &mut dyn Iterator, + variant_indices: impl Iterator + Clone, tag_field: usize, + dataful_variant_index: Option, ) -> SmallVec<&'ll DIType> { + let tag_base_type = super::tag_base_type(cx, enum_type_and_layout); + + let variant_names_type_di_node = build_variant_names_type_di_node( + cx, + enum_type_di_node, + variant_indices.clone().map(|variant_index| { + let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str()); + (variant_index, variant_name) + }), + ); + let variant_field_infos: SmallVec> = variant_indices .map(|variant_index| { let variant_layout = enum_type_and_layout.for_variant(cx, variant_index); + let variant_def = enum_adt_def.variant(variant_index); + + let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node( + cx, + enum_type_and_layout, + enum_type_di_node, + variant_index, + variant_def, + variant_layout, + ); + VariantFieldInfo { variant_index, - variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node( - cx, - enum_type_and_layout.ty, - enum_type_di_node, - variant_index, - enum_adt_def.variant(variant_index), - variant_layout, - ), + variant_struct_type_di_node, source_info: None, + discr: super::compute_discriminant_value(cx, enum_type_and_layout, variant_index), } }) .collect(); - let discr_type_name = cx.tcx.item_name(enum_adt_def.did()); - let tag_base_type = super::tag_base_type(cx, enum_type_and_layout); - let discr_type_di_node = super::build_enumeration_type_di_node( - cx, - discr_type_name.as_str(), - tag_base_type, - &mut enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| { - (discr, Cow::from(enum_adt_def.variant(variant_index).name.as_str())) - }), - enum_type_di_node, - ); - build_union_fields_for_direct_tag_enum_or_generator( cx, enum_type_and_layout, enum_type_di_node, &variant_field_infos, - discr_type_di_node, + variant_names_type_di_node, + tag_base_type, tag_field, + dataful_variant_index, ) } -fn build_union_fields_for_niche_tag_enum<'ll, 'tcx>( +// The base type of the VariantNames DW_AT_enumeration_type is always the same. +// It has nothing to do with the tag of the enum and just has to be big enough +// to hold all variant names. +fn variant_names_enum_base_type<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> Ty<'tcx> { + cx.tcx.types.u32 +} + +/// This function builds a DW_AT_enumeration_type that contains an entry for +/// each variant. Note that this has nothing to do with the discriminant. The +/// numeric value of each enumerator corresponds to the variant index. The +/// type is only used for efficiently encoding the name of each variant in +/// debuginfo. +fn build_variant_names_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - enum_adt_def: AdtDef<'tcx>, - enum_type_and_layout: TyAndLayout<'tcx>, - enum_type_di_node: &'ll DIType, - dataful_variant_index: VariantIdx, - variant_indices: &mut dyn Iterator, - tag_field: usize, -) -> SmallVec<&'ll DIType> { - let dataful_variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node( + containing_scope: &'ll DIType, + variants: impl Iterator)>, +) -> &'ll DIType { + // Create an enumerator for each variant. + super::build_enumeration_type_di_node( cx, - enum_type_and_layout.ty, - enum_type_di_node, - dataful_variant_index, - &enum_adt_def.variant(dataful_variant_index), - enum_type_and_layout.for_variant(cx, dataful_variant_index), - ); + "VariantNames", + variant_names_enum_base_type(cx), + variants.map(|(variant_index, variant_name)| (variant_name, variant_index.as_u32() as u64)), + containing_scope, + ) +} - let tag_base_type = super::tag_base_type(cx, enum_type_and_layout); - // Create an DW_TAG_enumerator for each variant except the dataful one. - let discr_type_di_node = super::build_enumeration_type_di_node( +fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + enum_or_generator_type_and_layout: TyAndLayout<'tcx>, + enum_or_generator_type_di_node: &'ll DIType, + variant_index: VariantIdx, + dataful_variant_index: Option, + variant_struct_type_di_node: &'ll DIType, + variant_names_type_di_node: &'ll DIType, + tag_base_type_di_node: &'ll DIType, + tag_base_type: Ty<'tcx>, + discr: DiscrResult, +) -> &'ll DIType { + type_map::build_type_with_children( cx, - "Discriminant$", - tag_base_type, - &mut variant_indices.filter_map(|variant_index| { - if let Some(discr_val) = - super::compute_discriminant_value(cx, enum_type_and_layout, variant_index) - { - let discr = Discr { val: discr_val as u128, ty: tag_base_type }; - let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str()); - Some((discr, variant_name)) - } else { - debug_assert_eq!(variant_index, dataful_variant_index); - None - } - }), - enum_type_di_node, - ); - - smallvec![ - build_field_di_node( - cx, - enum_type_di_node, - "dataful_variant", - size_and_align_of(enum_type_and_layout), - Size::ZERO, - DIFlags::FlagZero, - dataful_variant_struct_type_di_node, - ), - build_field_di_node( + type_map::stub( cx, - enum_type_di_node, - "discriminant", - cx.size_and_align_of(tag_base_type), - enum_type_and_layout.fields.offset(tag_field), - DIFlags::FlagZero, - discr_type_di_node, + Stub::Struct, + UniqueTypeId::for_enum_variant_struct_type_wrapper( + cx.tcx, + enum_or_generator_type_and_layout.ty, + variant_index, + ), + &variant_struct_wrapper_type_name(variant_index), + // NOTE: We use size and align of enum_type, not from variant_layout: + size_and_align_of(enum_or_generator_type_and_layout), + Some(enum_or_generator_type_di_node), + DIFlags::FlagArtificial, ), - ] + |cx, wrapper_struct_type_di_node| { + enum DiscrKind { + Exact(u64), + Exact128(u128), + Range(u64, u64), + Range128(u128, u128), + } + + let (tag_base_type_size, tag_base_type_align) = cx.size_and_align_of(tag_base_type); + let is_128_bits = tag_base_type_size.bits() > 64; + + let discr = match discr { + DiscrResult::NoDiscriminant => DiscrKind::Exact(SINGLE_VARIANT_VIRTUAL_DISR), + DiscrResult::Value(discr_val) => { + if is_128_bits { + DiscrKind::Exact128(discr_val) + } else { + debug_assert_eq!(discr_val, discr_val as u64 as u128); + DiscrKind::Exact(discr_val as u64) + } + } + DiscrResult::Range(min, max) => { + assert_eq!(Some(variant_index), dataful_variant_index); + if is_128_bits { + DiscrKind::Range128(min, max) + } else { + debug_assert_eq!(min, min as u64 as u128); + debug_assert_eq!(max, max as u64 as u128); + DiscrKind::Range(min as u64, max as u64) + } + } + }; + + let mut fields = SmallVec::new(); + + // We always have a field for the value + fields.push(build_field_di_node( + cx, + wrapper_struct_type_di_node, + "value", + size_and_align_of(enum_or_generator_type_and_layout), + Size::ZERO, + DIFlags::FlagArtificial, + variant_struct_type_di_node, + )); + + let build_assoc_const = + |name: &str, type_di_node: &'ll DIType, value: u64, align: Align| unsafe { + llvm::LLVMRustDIBuilderCreateStaticMemberType( + DIB(cx), + wrapper_struct_type_di_node, + name.as_ptr().cast(), + name.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + type_di_node, + DIFlags::FlagArtificial, + Some(cx.const_u64(value)), + align.bits() as u32, + ) + }; + + // We also always have an associated constant for the discriminant value + // of the variant. + fields.push(build_assoc_const( + ASSOC_CONST_DISCR_NAME, + variant_names_type_di_node, + variant_index.as_u32() as u64, + cx.align_of(variant_names_enum_base_type(cx)), + )); + + // Emit the discriminant value (or range) corresponding to the variant. + match discr { + DiscrKind::Exact(discr_val) => { + fields.push(build_assoc_const( + ASSOC_CONST_DISCR_EXACT, + tag_base_type_di_node, + discr_val, + tag_base_type_align, + )); + } + DiscrKind::Exact128(discr_val) => { + let align = cx.align_of(cx.tcx.types.u64); + let type_di_node = type_di_node(cx, cx.tcx.types.u64); + let Split128 { hi, lo } = split_128(discr_val); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_EXACT_LO, + type_di_node, + lo, + align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_EXACT_HI, + type_di_node, + hi, + align, + )); + } + DiscrKind::Range(begin, end) => { + fields.push(build_assoc_const( + ASSOC_CONST_DISCR_BEGIN, + tag_base_type_di_node, + begin, + tag_base_type_align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR_END, + tag_base_type_di_node, + end, + tag_base_type_align, + )); + } + DiscrKind::Range128(begin, end) => { + let align = cx.align_of(cx.tcx.types.u64); + let type_di_node = type_di_node(cx, cx.tcx.types.u64); + let Split128 { hi: begin_hi, lo: begin_lo } = split_128(begin); + let Split128 { hi: end_hi, lo: end_lo } = split_128(end); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_BEGIN_HI, + type_di_node, + begin_hi, + align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_BEGIN_LO, + type_di_node, + begin_lo, + align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_END_HI, + type_di_node, + end_hi, + align, + )); + + fields.push(build_assoc_const( + ASSOC_CONST_DISCR128_END_LO, + type_di_node, + end_lo, + align, + )); + } + } + + fields + }, + NO_GENERICS, + ) + .di_node +} + +struct Split128 { + hi: u64, + lo: u64, +} + +fn split_128(value: u128) -> Split128 { + Split128 { hi: (value >> 64) as u64, lo: value as u64 } } fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( @@ -370,6 +598,21 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( let common_upvar_names = closure_saved_names_of_captured_variables(cx.tcx, generator_def_id); let variant_range = generator_substs.variant_range(generator_def_id, cx.tcx); + let tag_base_type = tag_base_type(cx, generator_type_and_layout); + + let variant_names_type_di_node = build_variant_names_type_di_node( + cx, + generator_type_di_node, + variant_range + .clone() + .map(|variant_index| (variant_index, GeneratorSubsts::variant_name(variant_index))), + ); + + let discriminants: FxHashMap = generator_substs + .discriminants(generator_def_id, cx.tcx) + .map(|(variant_index, discr)| (variant_index, DiscrResult::Value(discr.val))) + .collect(); + // Build the type node for each field. let variant_field_infos: SmallVec> = variant_range .map(|variant_index| { @@ -391,29 +634,24 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( None }; - VariantFieldInfo { variant_index, variant_struct_type_di_node, source_info } + VariantFieldInfo { + variant_index, + variant_struct_type_di_node, + source_info, + discr: discriminants[&variant_index], + } }) .collect(); - let tag_base_type = tag_base_type(cx, generator_type_and_layout); - let discr_type_name = "Discriminant$"; - let discr_type_di_node = super::build_enumeration_type_di_node( - cx, - discr_type_name, - tag_base_type, - &mut generator_substs - .discriminants(generator_def_id, cx.tcx) - .map(|(variant_index, discr)| (discr, GeneratorSubsts::variant_name(variant_index))), - generator_type_di_node, - ); - build_union_fields_for_direct_tag_enum_or_generator( cx, generator_type_and_layout, generator_type_di_node, &variant_field_infos[..], - discr_type_di_node, + variant_names_type_di_node, + tag_base_type, tag_field, + None, ) } @@ -425,8 +663,11 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( enum_type_di_node: &'ll DIType, variant_field_infos: &[VariantFieldInfo<'ll>], discr_type_di_node: &'ll DIType, + tag_base_type: Ty<'tcx>, tag_field: usize, + dataful_variant_index: Option, ) -> SmallVec<&'ll DIType> { + let tag_base_type_di_node = type_di_node(cx, tag_base_type); let mut unions_fields = SmallVec::with_capacity(variant_field_infos.len() + 1); // We create a field in the union for each variant ... @@ -435,9 +676,23 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( .source_info .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)); - let field_name = variant_union_field_name(variant_member_info.variant_index); + let field_name = + variant_union_field_name(variant_member_info.variant_index, dataful_variant_index); let (size, align) = size_and_align_of(enum_type_and_layout); + let variant_struct_type_wrapper = build_variant_struct_wrapper_type_di_node( + cx, + enum_type_and_layout, + enum_type_di_node, + variant_member_info.variant_index, + dataful_variant_index, + variant_member_info.variant_struct_type_di_node, + discr_type_di_node, + tag_base_type_di_node, + tag_base_type, + variant_member_info.discr, + ); + // We use LLVMRustDIBuilderCreateMemberType() member type directly because // the build_field_di_node() function does not support specifying a source location, // which is something that we don't do anywhere else. @@ -456,7 +711,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( // Union fields are always at offset zero Size::ZERO.bits(), DIFlags::FlagZero, - variant_member_info.variant_struct_type_di_node, + variant_struct_type_wrapper, ) } })); @@ -466,16 +721,53 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( cx.size_and_align_of(super::tag_base_type(cx, enum_type_and_layout)) ); - // ... and a field for the discriminant. - unions_fields.push(build_field_di_node( - cx, - enum_type_di_node, - "discriminant", - cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty), - enum_type_and_layout.fields.offset(tag_field), - DIFlags::FlagZero, - discr_type_di_node, - )); + // ... and a field for the tag. If the tag is 128 bits wide, this will actually + // be two 64-bit fields. + let is_128_bits = cx.size_of(tag_base_type).bits() > 64; + + if is_128_bits { + let type_di_node = type_di_node(cx, cx.tcx.types.u64); + let size_and_align = cx.size_and_align_of(cx.tcx.types.u64); + + let (lo_offset, hi_offset) = match cx.tcx.data_layout.endian { + Endian::Little => (0, 8), + Endian::Big => (8, 0), + }; + + let tag_field_offset = enum_type_and_layout.fields.offset(tag_field).bytes(); + let lo_offset = Size::from_bytes(tag_field_offset + lo_offset); + let hi_offset = Size::from_bytes(tag_field_offset + hi_offset); + + unions_fields.push(build_field_di_node( + cx, + enum_type_di_node, + TAG_FIELD_NAME_128_LO, + size_and_align, + lo_offset, + DIFlags::FlagZero, + type_di_node, + )); + + unions_fields.push(build_field_di_node( + cx, + enum_type_di_node, + TAG_FIELD_NAME_128_HI, + size_and_align, + hi_offset, + DIFlags::FlagZero, + type_di_node, + )); + } else { + unions_fields.push(build_field_di_node( + cx, + enum_type_di_node, + TAG_FIELD_NAME, + cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty), + enum_type_and_layout.fields.offset(tag_field), + DIFlags::FlagZero, + tag_base_type_di_node, + )); + } unions_fields } @@ -485,9 +777,13 @@ struct VariantFieldInfo<'ll> { variant_index: VariantIdx, variant_struct_type_di_node: &'ll DIType, source_info: Option<(&'ll DIFile, c_uint)>, + discr: DiscrResult, } -fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> { +fn variant_union_field_name( + variant_index: VariantIdx, + dataful_variant_index: Option, +) -> Cow<'static, str> { const PRE_ALLOCATED: [&str; 16] = [ "variant0", "variant1", @@ -507,8 +803,38 @@ fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> { "variant15", ]; + if Some(variant_index) == dataful_variant_index { + return Cow::from("variant_fallback"); + } + PRE_ALLOCATED .get(variant_index.as_usize()) .map(|&s| Cow::from(s)) .unwrap_or_else(|| format!("variant{}", variant_index.as_usize()).into()) } + +fn variant_struct_wrapper_type_name(variant_index: VariantIdx) -> Cow<'static, str> { + const PRE_ALLOCATED: [&str; 16] = [ + "Variant0", + "Variant1", + "Variant2", + "Variant3", + "Variant4", + "Variant5", + "Variant6", + "Variant7", + "Variant8", + "Variant9", + "Variant10", + "Variant11", + "Variant12", + "Variant13", + "Variant14", + "Variant15", + ]; + + PRE_ALLOCATED + .get(variant_index.as_usize()) + .map(|&s| Cow::from(s)) + .unwrap_or_else(|| format!("Variant{}", variant_index.as_usize()).into()) +} 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 73e01d0453b25..9b3d080bfd6aa 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -10,7 +10,6 @@ use rustc_middle::{ ty::{ self, layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout}, - util::Discr, AdtDef, GeneratorSubsts, Ty, VariantDef, }, }; @@ -90,8 +89,11 @@ fn build_c_style_enum_di_node<'ll, 'tcx>( cx, &compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false), tag_base_type(cx, enum_type_and_layout), - &mut enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| { - (discr, Cow::from(enum_adt_def.variant(variant_index).name.as_str())) + enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| { + let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str()); + // Is there anything we can do to support 128-bit C-Style enums? + let value = discr.val as u64; + (name, value) }), containing_scope, ), @@ -152,7 +154,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, type_name: &str, base_type: Ty<'tcx>, - variants: &mut dyn Iterator, Cow<'tcx, str>)>, + enumerators: impl Iterator, u64)>, containing_scope: &'ll DIType, ) -> &'ll DIType { let is_unsigned = match base_type.kind() { @@ -161,18 +163,15 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( _ => bug!("build_enumeration_type_di_node() called with non-integer tag type."), }; - let enumerator_di_nodes: SmallVec> = variants - .map(|(discr, variant_name)| { - unsafe { - Some(llvm::LLVMRustDIBuilderCreateEnumerator( - DIB(cx), - variant_name.as_ptr().cast(), - variant_name.len(), - // FIXME: what if enumeration has i128 discriminant? - discr.val as i64, - is_unsigned, - )) - } + let enumerator_di_nodes: SmallVec> = enumerators + .map(|(name, value)| unsafe { + Some(llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr().cast(), + name.len(), + value as i64, + is_unsigned, + )) }) .collect(); @@ -247,23 +246,27 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( /// and a DW_TAG_member for each field (but not the discriminant). fn build_enum_variant_struct_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - enum_type: Ty<'tcx>, + enum_type_and_layout: TyAndLayout<'tcx>, enum_type_di_node: &'ll DIType, variant_index: VariantIdx, variant_def: &VariantDef, variant_layout: TyAndLayout<'tcx>, ) -> &'ll DIType { - debug_assert_eq!(variant_layout.ty, enum_type); + debug_assert_eq!(variant_layout.ty, enum_type_and_layout.ty); type_map::build_type_with_children( cx, type_map::stub( cx, Stub::Struct, - UniqueTypeId::for_enum_variant_struct_type(cx.tcx, enum_type, variant_index), + UniqueTypeId::for_enum_variant_struct_type( + cx.tcx, + enum_type_and_layout.ty, + variant_index, + ), variant_def.name.as_str(), // NOTE: We use size and align of enum_type, not from variant_layout: - cx.size_and_align_of(enum_type), + size_and_align_of(enum_type_and_layout), Some(enum_type_di_node), DIFlags::FlagZero, ), @@ -290,9 +293,9 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>( type_di_node(cx, field_layout.ty), ) }) - .collect() + .collect::>() }, - |cx| build_generic_type_param_di_nodes(cx, enum_type), + |cx| build_generic_type_param_di_nodes(cx, enum_type_and_layout.ty), ) .di_node } @@ -398,6 +401,19 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>( .di_node } +#[derive(Copy, Clone)] +enum DiscrResult { + NoDiscriminant, + Value(u128), + Range(u128, u128), +} + +impl DiscrResult { + fn opt_single_val(&self) -> Option { + if let Self::Value(d) = *self { Some(d) } else { None } + } +} + /// Returns the discriminant value corresponding to the variant index. /// /// Will return `None` if there is less than two variants (because then the enum won't have) @@ -407,12 +423,11 @@ fn compute_discriminant_value<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, enum_type_and_layout: TyAndLayout<'tcx>, variant_index: VariantIdx, -) -> Option { +) -> DiscrResult { match enum_type_and_layout.layout.variants() { - &Variants::Single { .. } => None, - &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => Some( - enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val - as u64, + &Variants::Single { .. } => DiscrResult::NoDiscriminant, + &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value( + enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val, ), &Variants::Multiple { tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant }, @@ -420,17 +435,26 @@ fn compute_discriminant_value<'ll, 'tcx>( .. } => { if variant_index == dataful_variant { - None + let valid_range = enum_type_and_layout + .for_variant(cx, variant_index) + .largest_niche + .as_ref() + .unwrap() + .valid_range; + + let min = valid_range.start.min(valid_range.end); + let min = tag.size(cx).truncate(min); + + let max = valid_range.start.max(valid_range.end); + let max = tag.size(cx).truncate(max); + + DiscrResult::Range(min, max) } else { let value = (variant_index.as_u32() as u128) .wrapping_sub(niche_variants.start().as_u32() as u128) .wrapping_add(niche_start); let value = tag.size(cx).truncate(value); - // NOTE(eddyb) do *NOT* remove this assert, until - // we pass the full 128-bit value to LLVM, otherwise - // truncation will be silent and remain undetected. - assert_eq!(value as u64 as u128, value); - Some(value as u64) + DiscrResult::Value(value) } } } 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 f1935e0ec31af..dae90a43f2659 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -88,7 +88,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( variant_name: Cow::from(enum_adt_def.variant(variant_index).name.as_str()), variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node( cx, - enum_type, + enum_type_and_layout, enum_type_di_node, variant_index, enum_adt_def.variant(variant_index), @@ -413,7 +413,13 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( enum_type_and_layout.size.bits(), enum_type_and_layout.align.abi.bits() as u32, Size::ZERO.bits(), - discr_value.map(|v| cx.const_u64(v)), + discr_value.opt_single_val().map(|value| { + // NOTE(eddyb) do *NOT* remove this assert, until + // we pass the full 128-bit value to LLVM, otherwise + // truncation will be silent and remain undetected. + assert_eq!(value as u64 as u128, value); + cx.const_u64(value as u64) + }), DIFlags::FlagZero, variant_member_info.variant_struct_type_di_node, ) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index ce2f419c4acdc..e30622cbdced6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -47,6 +47,8 @@ pub(super) enum UniqueTypeId<'tcx> { VariantPart(Ty<'tcx>, private::HiddenZst), /// The ID for the artificial struct type describing a single enum variant. VariantStructType(Ty<'tcx>, VariantIdx, private::HiddenZst), + /// The ID for the additional wrapper struct type describing an enum variant in CPP-like mode. + VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst), /// The ID of the artificial type we create for VTables. VTableTy(Ty<'tcx>, Option>, private::HiddenZst), } @@ -71,6 +73,15 @@ impl<'tcx> UniqueTypeId<'tcx> { UniqueTypeId::VariantStructType(enum_ty, variant_idx, private::HiddenZst) } + pub fn for_enum_variant_struct_type_wrapper( + tcx: TyCtxt<'tcx>, + enum_ty: Ty<'tcx>, + variant_idx: VariantIdx, + ) -> Self { + debug_assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty)); + UniqueTypeId::VariantStructTypeCppLikeWrapper(enum_ty, variant_idx, private::HiddenZst) + } + pub fn for_vtable_ty( tcx: TyCtxt<'tcx>, self_type: Ty<'tcx>, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3139f93bfefae..89611fc0dee1b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2079,6 +2079,19 @@ extern "C" { Ty: &'a DIType, ) -> &'a DIType; + pub fn LLVMRustDIBuilderCreateStaticMemberType<'a>( + Builder: &DIBuilder<'a>, + Scope: &'a DIDescriptor, + Name: *const c_char, + NameLen: size_t, + File: &'a DIFile, + LineNo: c_uint, + Ty: &'a DIType, + Flags: DIFlags, + val: Option<&'a Value>, + AlignInBits: u32, + ) -> &'a DIDerivedType; + pub fn LLVMRustDIBuilderCreateLexicalBlock<'a>( Builder: &DIBuilder<'a>, Scope: &'a DIScope, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 8cd5a0fc24759..1dde6ae8edf12 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -18,11 +18,10 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability}; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, ExistentialProjection, GeneratorSubsts, ParamEnv, Ty, TyCtxt}; -use rustc_target::abi::{Integer, TagEncoding, Variants}; +use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt}; +use rustc_target::abi::Integer; use smallvec::SmallVec; -use std::borrow::Cow; use std::fmt::Write; use crate::debuginfo::wants_c_like_enum_debuginfo; @@ -98,7 +97,6 @@ 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); @@ -395,7 +393,6 @@ fn push_debuginfo_type_name<'tcx>( if cpp_like_debuginfo && t.is_generator() { 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_generator_name(tcx, def_id, substs, true, output, visited); @@ -428,58 +425,17 @@ fn push_debuginfo_type_name<'tcx>( /// MSVC names enums differently than other platforms so that the debugging visualization // format (natvis) is able to understand enums and render the active variant correctly in the - // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and - // `EnumMemberDescriptionFactor::create_member_descriptions`. + // 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)); - let ty = ty_and_layout.ty; - output.push_str("enum$<"); push_inner(output, visited); - - let variant_name = |variant_index| match ty.kind() { - ty::Adt(adt_def, _) => { - debug_assert!(adt_def.is_enum()); - Cow::from(adt_def.variant(variant_index).name.as_str()) - } - ty::Generator(..) => GeneratorSubsts::variant_name(variant_index), - _ => unreachable!(), - }; - - if let Variants::Multiple { - tag_encoding: TagEncoding::Niche { dataful_variant, .. }, - tag, - variants, - .. - } = &ty_and_layout.variants - { - let dataful_variant_layout = &variants[*dataful_variant]; - - // calculate the range of values for the dataful variant - let dataful_discriminant_range = - dataful_variant_layout.largest_niche().unwrap().valid_range; - - let min = dataful_discriminant_range.start; - let min = tag.size(&tcx).truncate(min); - - let max = dataful_discriminant_range.end; - let max = tag.size(&tcx).truncate(max); - - let dataful_variant_name = variant_name(*dataful_variant); - write!(output, ", {}, {}, {}", min, max, dataful_variant_name).unwrap(); - } else if let Variants::Single { index: variant_idx } = &ty_and_layout.variants { - // Uninhabited enums can't be constructed and should never need to be visualized so - // skip this step for them. - if !ty_and_layout.abi.is_uninhabited() { - write!(output, ", {}", variant_name(*variant_idx)).unwrap(); - } - } push_close_angle_bracket(true, output); } diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 30ff364210da8..4172ce3bb306a 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -172,7 +172,9 @@ impl IndexVec { } #[inline] - pub fn indices(&self) -> impl DoubleEndedIterator + ExactSizeIterator + 'static { + pub fn indices( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator + Clone + 'static { (0..self.len()).map(|n| I::new(n)) } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 5f5b5de790e43..f9bffe6d82392 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -924,6 +924,30 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType( fromRust(Flags), unwrapDI(Ty))); } +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType( + LLVMRustDIBuilderRef Builder, + LLVMMetadataRef Scope, + const char *Name, + size_t NameLen, + LLVMMetadataRef File, + unsigned LineNo, + LLVMMetadataRef Ty, + LLVMRustDIFlags Flags, + LLVMValueRef val, + uint32_t AlignInBits +) { + return wrap(Builder->createStaticMemberType( + unwrapDI(Scope), + StringRef(Name, NameLen), + unwrapDI(File), + LineNo, + unwrapDI(Ty), + fromRust(Flags), + unwrap(val), + AlignInBits + )); +} + extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock( LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Line, unsigned Col) { diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 558536fa613a5..9f1aa525d1f55 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -1,4 +1,4 @@ - + {(char*)data_ptr,[length]s8} @@ -150,76 +150,122 @@ - + - - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} - {tag(),en} + + + + - - - {tag(),en} - - variant0 - variant1 - variant2 - variant3 - variant4 - variant5 - variant6 - variant7 - variant8 - variant9 - variant10 - variant11 - variant12 - variant13 - variant14 - variant15 - - + + + + - - - {"$T2",sb} - - - {"$T2",sb} - - $T2 - - + + + + + + - - - - - {"$T4",sb}({dataful_variant}) - {discriminant,en} - - dataful_variant - - {"$T4",sb} - - - {discriminant,en} - + + + + + + + + + + + + + + + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} + + {variant_fallback.NAME,en} + + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} + + {variant_fallback.NAME,en} + + + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value + + variant_fallback.value + + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value + + variant_fallback.value diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs index d6d7e5b44aafc..95b0819cc38ba 100644 --- a/src/test/debuginfo/generator-objects.rs +++ b/src/test/debuginfo/generator-objects.rs @@ -42,13 +42,11 @@ // cdb-command: g // cdb-command: dx b // cdb-check: b : Unresumed [Type: enum$] -// cdb-check: [variant] : Unresumed // cdb-check: [+0x[...]] _ref__a : 0x[...] : 5 [Type: int *] // cdb-command: g // cdb-command: dx b // cdb-check: b : Suspend0 [Type: enum$] -// cdb-check: [variant] : Suspend0 // cdb-check: [+0x[...]] c : 6 [Type: int] // cdb-check: [+0x[...]] d : 7 [Type: int] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 5 [Type: int *] @@ -56,7 +54,6 @@ // cdb-command: g // cdb-command: dx b // cdb-check: b : Suspend1 [Type: enum$] -// cdb-check: [variant] : Suspend1 // cdb-check: [+0x[...]] c : 7 [Type: int] // cdb-check: [+0x[...]] d : 8 [Type: int] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *] @@ -64,8 +61,6 @@ // cdb-command: g // cdb-command: dx b // cdb-check: b : Returned [Type: enum$] -// cdb-check: [] [Type: enum$] -// cdb-check: [variant] : Returned // cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *] #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index a153a9a42289a..b1ca5dfa1c77c 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -4,69 +4,110 @@ // cdb-command: g // cdb-command: dx a -// cdb-check:a : Some({...}) [Type: enum$, 2, 16, Some>] -// cdb-check: [] [Type: enum$, 2, 16, Some>] -// cdb-check: [variant] : Some +// cdb-check:a : Some [Type: enum$ >] // cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] // cdb-command: dx b -// cdb-check:b : None [Type: enum$, 2, 16, Some>] -// cdb-check: [] [Type: enum$, 2, 16, Some>] -// cdb-check: [variant] : None +// cdb-check:b : None [Type: enum$ >] // cdb-command: dx c -// cdb-check:c : Tag1 [Type: enum$] -// cdb-check: [] [Type: enum$] -// cdb-check: [variant] : Tag1 +// cdb-check:c : Tag1 [Type: enum$] // cdb-command: dx d -// cdb-check:d : Data({...}) [Type: enum$] -// cdb-check: [] [Type: enum$] -// cdb-check: [variant] : Data +// cdb-check:d : Data [Type: enum$] // cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] // cdb-command: dx e -// cdb-check:e : Tag2 [Type: enum$] -// cdb-check: [] [Type: enum$] -// cdb-check: [variant] : Tag2 +// cdb-check:e : Tag2 [Type: enum$] // cdb-command: dx f -// cdb-check:f : Some({...}) [Type: enum$ >, 1, [...], Some>] -// cdb-check: [] [Type: enum$ >, 1, [...], Some>] -// cdb-check: [variant] : Some +// cdb-check:f : Some [Type: enum$ > >] // cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] // cdb-command: dx g -// cdb-check:g : None [Type: enum$ >, 1, [...], Some>] -// cdb-check: [] [Type: enum$ >, 1, [...], Some>] -// cdb-check: [variant] : None +// cdb-check:g : None [Type: enum$ > >] // cdb-command: dx h // cdb-check:h : Some [Type: enum$ >] -// cdb-check: [] [Type: enum$ >] -// cdb-check: [variant] : Some // cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] // cdb-command: dx i // cdb-check:i : None [Type: enum$ >] -// cdb-check: [] [Type: enum$ >] -// cdb-check: [variant] : None // cdb-command: dx j // cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] // cdb-command: dx k -// cdb-check:k : Some({...}) [Type: enum$, 1, [...], Some>] -// cdb-check: [] [Type: enum$, 1, [...], Some>] -// cdb-check: [variant] : Some +// cdb-check:k : Some [Type: enum$ >] // cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] // cdb-command: dx l -// cdb-check:l : Ok [Type: enum$ >, Ok>] -// cdb-check: [] [Type: enum$ >, Ok>] -// cdb-check: [variant] : Ok +// cdb-check:l : Ok [Type: enum$ > >] // cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] +// cdb-command: dx niche128_some +// cdb-check:niche128_some : Some [Type: enum$ >] +// Note: we can't actually read the value of the field because CDB cannot handle 128 bit integers. +// cdb-check: [+0x000] __0 [...] [Type: core::num::nonzero::NonZeroI128] + +// cdb-command: dx niche128_none +// cdb-check: niche128_none : None [Type: enum$ >] + +// cdb-command: dx niche_w_fields_1_some,d +// cdb-check: niche_w_fields_1_some,d : A [Type: enum$] +// cdb-check: [+0x[...]] __0 : 0x[...] : 77 [Type: unsigned char *] +// cdb-check: [+0x[...]] __1 : 7 [Type: unsigned int] + +// cdb-command: dx niche_w_fields_1_none,d +// cdb-check: niche_w_fields_1_none,d : B [Type: enum$] +// cdb-check: [+0x[...]] __0 : 99 [Type: unsigned int] + +// cdb-command: dx niche_w_fields_2_some,d +// cdb-check: niche_w_fields_2_some,d : A [Type: enum$] +// cdb-check: [] [Type: enum$] +// cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZeroU32] +// cdb-check: [+0x[...]] __1 : 900 [Type: unsigned __int64] + +// cdb-command: dx niche_w_fields_2_none,d +// cdb-check: niche_w_fields_2_none,d : B [Type: enum$] +// cdb-check: [+0x[...]] __0 : 1000 [Type: unsigned __int64] + +// cdb-command: dx niche_w_fields_3_some,d +// cdb-check: niche_w_fields_3_some,d : A [Type: enum$] +// cdb-check: [+0x[...]] __0 : 137 [Type: unsigned char] +// cdb-check: [+0x[...]] __1 : true [Type: bool] + +// cdb-command: dx niche_w_fields_3_niche1,d +// cdb-check: niche_w_fields_3_niche1,d : B [Type: enum$] +// cdb-check: [+0x[...]] __0 : 12 [Type: unsigned char] + +// cdb-command: dx niche_w_fields_3_niche2,d +// cdb-check: niche_w_fields_3_niche2,d : C [Type: enum$] +// cdb-check: [+0x[...]] __0 : false [Type: bool] + +// cdb-command: dx niche_w_fields_3_niche3,d +// cdb-check: niche_w_fields_3_niche3,d : D [Type: enum$] +// cdb-check: [+0x[...]] __0 : 34 [Type: unsigned char] + +// cdb-command: dx niche_w_fields_3_niche4,d +// cdb-check: niche_w_fields_3_niche4,d : E [Type: enum$] +// cdb-check: [+0x[...]] __0 : 56 [Type: unsigned char] + +// cdb-command: dx niche_w_fields_3_niche5,d +// cdb-check: niche_w_fields_3_niche5,d : F [Type: enum$] + +// cdb-command: dx -r3 niche_w_fields_std_result_ok,d +// cdb-check: niche_w_fields_std_result_ok,d : Ok [Type: enum$,alloc::alloc::Global>,u64> >] +// cdb-check: [+0x[...]] __0 [Type: alloc::boxed::Box,alloc::alloc::Global>] +// cdb-check: [+0x[...]] data_ptr : [...] +// cdb-check: [+0x[...]] length : 3 [...] + +// cdb-command: dx -r3 niche_w_fields_std_result_err,d +// cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum$,alloc::alloc::Global>,u64> >] +// cdb-check: [+0x[...]] __0 : 789 [Type: unsigned __int64] + +use std::num::{NonZeroI128, NonZeroU32}; + pub enum CStyleEnum { Low = 2, High = 16, @@ -80,6 +121,27 @@ pub enum NicheLayoutEnum { pub enum Empty {} +// The following three types will use a niche layout once +// https://github.com/rust-lang/rust/pull/94075 is merged: +enum NicheLayoutWithFields1<'a> { + A(&'a u8, u32), + B(u32), +} + +enum NicheLayoutWithFields2 { + A(NonZeroU32, usize), + B(usize), +} + +enum NicheLayoutWithFields3 { + A(u8, bool), + B(u8), + C(bool), + D(u8), + E(u8), + F, +} + fn main() { let a = Some(CStyleEnum::Low); let b = Option::::None; @@ -93,6 +155,24 @@ fn main() { let j = CStyleEnum::High; let k = Some("IAMA optional string!".to_string()); let l = Result::::Ok(42); + let niche128_some = Some(NonZeroI128::new(123456).unwrap()); + let niche128_none: Option = None; + + let niche_w_fields_1_some = NicheLayoutWithFields1::A(&77, 7); + let niche_w_fields_1_none = NicheLayoutWithFields1::B(99); + + let niche_w_fields_2_some = NicheLayoutWithFields2::A(NonZeroU32::new(800).unwrap(), 900); + let niche_w_fields_2_none = NicheLayoutWithFields2::B(1000); + + let niche_w_fields_3_some = NicheLayoutWithFields3::A(137, true); + let niche_w_fields_3_niche1 = NicheLayoutWithFields3::B(12); + let niche_w_fields_3_niche2 = NicheLayoutWithFields3::C(false); + let niche_w_fields_3_niche3 = NicheLayoutWithFields3::D(34); + let niche_w_fields_3_niche4 = NicheLayoutWithFields3::E(56); + let niche_w_fields_3_niche5 = NicheLayoutWithFields3::F; + + let niche_w_fields_std_result_ok: Result, u64> = Ok(vec![1, 2, 3].into()); + let niche_w_fields_std_result_err: Result, u64> = Err(789); zzz(); // #break } diff --git a/src/test/debuginfo/msvc-scalarpair-params.rs b/src/test/debuginfo/msvc-scalarpair-params.rs index 3846fb42f81a5..38a9633c9bfce 100644 --- a/src/test/debuginfo/msvc-scalarpair-params.rs +++ b/src/test/debuginfo/msvc-scalarpair-params.rs @@ -19,11 +19,9 @@ // cdb-command: dx o1 // cdb-check:o1 : Some [Type: enum$ >] -// cdb-check: [variant] : Some // cdb-check: [+0x004] __0 : 0x4d2 [Type: [...]] // cdb-command: dx o2 // cdb-check:o2 : Some [Type: enum$ >] -// cdb-check: [variant] : Some // cdb-check: [+0x008] __0 : 0x162e [Type: unsigned __int64] // cdb-command: g @@ -89,7 +87,7 @@ fn slice(s: &[u8]) { zzz(); // #break } -fn zzz() { } +fn zzz() {} fn main() { range(10..12, 20..30); diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 55a4ecc1c1a29..fe44c42aa5312 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -39,7 +39,6 @@ // gdb-command: print some_string // gdb-check:$8 = Some = {"IAMA "...} - // === LLDB TESTS ================================================================================== // lldb-command: run @@ -65,7 +64,6 @@ // lldb-command: print os_string // lldb-check:[...]$6 = "IAMA OS string 😃"[...] - // === CDB TESTS ================================================================================== // cdb-command: g @@ -120,18 +118,15 @@ // cdb-command: dx some // cdb-check:some : Some [Type: enum$ >] // cdb-check: [] [Type: enum$ >] -// cdb-check: [variant] : Some // cdb-check: [+0x002] __0 : 8 [Type: short] // cdb-command: dx none // cdb-check:none : None [Type: enum$ >] // cdb-check: [] [Type: enum$ >] -// cdb-check: [variant] : None // cdb-command: dx some_string -// cdb-check:some_string : Some({...}) [Type: enum$, 1, [...], Some>] -// cdb-check: [] [Type: enum$, 1, [...], Some>] -// cdb-check: [variant] : Some +// cdb-check:some_string : Some [Type: enum$ >] +// cdb-check: [] [Type: enum$ >] // cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] // cdb-command: dx linkedlist @@ -153,7 +148,6 @@ use std::collections::{LinkedList, VecDeque}; use std::ffi::OsString; fn main() { - // &[] let slice: &[i32] = &[0, 1, 2, 3]; @@ -188,4 +182,6 @@ fn main() { zzz(); // #break } -fn zzz() { () } +fn zzz() { + () +} diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index b040a6e74947d..426d9ddf2517b 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -240,14 +240,14 @@ // cdb-check:struct tuple$ rust_fn_with_return_value = [...] // cdb-check:struct tuple$ >),usize> unsafe_fn = [...] // cdb-check:struct tuple$ extern_c_fn = [...] -// cdb-check:struct tuple$ >,enum$ >, 1, [...], Some>),usize> rust_fn = [...] +// cdb-check:struct tuple$ >,enum$ > >),usize> rust_fn = [...] // cdb-command:dv /t *_function* // cdb-check:struct tuple$, ...),usize> variadic_function = [...] // cdb-check:struct tuple$ generic_function_struct3 = [...] // cdb-check:struct tuple$ generic_function_int = [...] // cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("rust_fn") // cdb-check:Return Type: void -// cdb-check:Parameter Types: enum$ >,enum$ >, 1, [...], Some> +// cdb-check:Parameter Types: enum$ >,enum$ > > // cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("rust_fn_with_return_value") // cdb-check:Return Type: usize // cdb-check:Parameter Types: f64 From 063ebfa5707015f895fc50c3a1dd70ab6867bc9b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 7 Jul 2022 15:01:43 +0200 Subject: [PATCH 02/15] Use enum2<_> instead of enum<_> for Cpp-like debuginfo enum type names. And add more comments about niche tag enum encoding. --- .../src/debuginfo/metadata/enums/cpp_like.rs | 27 +++++++--- .../src/debuginfo/type_names.rs | 4 +- src/etc/natvis/intrinsic.natvis | 4 +- src/test/debuginfo/generator-objects.rs | 8 +-- src/test/debuginfo/msvc-pretty-enums.rs | 51 +++++++++---------- src/test/debuginfo/msvc-scalarpair-params.rs | 4 +- src/test/debuginfo/mutex.rs | 5 +- src/test/debuginfo/pretty-std.rs | 12 ++--- src/test/debuginfo/result-types.rs | 11 ++-- src/test/debuginfo/type-names.rs | 34 ++++++------- 10 files changed, 87 insertions(+), 73 deletions(-) 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 55bdd29d67cde..7a32e2550433d 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 @@ -68,7 +68,7 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// It's roughly equivalent to the following C/C++ code: /// /// ```c -/// union enum$<{fully-qualified-name}> { +/// union enum2$<{fully-qualified-name}> { /// struct Variant0 { /// struct {name-of-variant-0} { /// @@ -91,12 +91,27 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// } /// ``` /// -/// As you can see, the type name is wrapped `enum$`. This way we can have a -/// single NatVis rule for handling all enums. +/// As you can see, the type name is wrapped in `enum2$<_>`. This way we can +/// have a single NatVis rule for handling all enums. The `2` in `enum2$<_>` +/// is an encoding version tag, so that debuggers can decide to decode this +/// differently than the previous `enum$<_>` encoding emitted by earlier +/// compiler versions. /// -/// For niche-tag enums, a variant might correspond to a range of tag values. -/// In that case the variant struct has a `DISCR_BEGIN` and `DISCR_END` field -/// instead of DISCR_EXACT. +/// Niche-tag enums have one special variant, usually called the +/// "dataful variant". This variant has a field that +/// doubles as the tag of the enum. The variant is active when the value of +/// that field is within a pre-defined range. Therefore the variant struct +/// has a `DISCR_BEGIN` and `DISCR_END` field instead of `DISCR_EXACT` in +/// that case. Both `DISCR_BEGIN` and `DISCR_END` are inclusive bounds. +/// Note that these ranges can wrap around, so that `DISCR_END < DISCR_BEGIN`. +/// +/// The field in the top-level union that corresponds to the dataful variant +/// is called `variant_fallback` instead of `variant`. This is mainly +/// an optimization that enables a shorter NatVis definition. That way we +/// only need to specify a `tag == variantX.DISCR_EXACT` entry for the indexed +/// variants. Otherwise we'd need to have that and then an additional entry +/// checking `in_range(variantX.DISCR_BEGIN, variantX.DISCR_END)` for each +/// index. /// /// Single-variant enums don't actually have a tag field. In this case we /// emit a static tag field (that always has the value 0) so we can use the diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1dde6ae8edf12..135ed680da2dc 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -389,7 +389,7 @@ fn push_debuginfo_type_name<'tcx>( // Name will be "{closure_env#0}", "{generator_env#0}", or // "{async_fn_env#0}", etc. // In the case of cpp-like debuginfo, the name additionally gets wrapped inside of - // an artificial `enum$<>` type, as defined in msvc_enum_fallback(). + // an artificial `enum2$<>` type, as defined in msvc_enum_fallback(). if cpp_like_debuginfo && t.is_generator() { let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap(); msvc_enum_fallback( @@ -434,7 +434,7 @@ fn push_debuginfo_type_name<'tcx>( visited: &mut FxHashSet>, ) { debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout)); - output.push_str("enum$<"); + output.push_str("enum2$<"); push_inner(output, visited); push_close_angle_bracket(true, output); } diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 9f1aa525d1f55..82f47b7814e04 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -1,4 +1,4 @@ - + {(char*)data_ptr,[length]s8} @@ -154,7 +154,7 @@ This is the visualizer for all enums. It takes care of selecting the active variant. See `compiler\rustc_codegen_llvm\src\debuginfo\metadata\enums\cpp_like.rs` for more information. --> - + diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs index 95b0819cc38ba..11c4ae2f65929 100644 --- a/src/test/debuginfo/generator-objects.rs +++ b/src/test/debuginfo/generator-objects.rs @@ -41,26 +41,26 @@ // cdb-command: g // cdb-command: dx b -// cdb-check: b : Unresumed [Type: enum$] +// cdb-check: b : Unresumed [Type: enum2$] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 5 [Type: int *] // cdb-command: g // cdb-command: dx b -// cdb-check: b : Suspend0 [Type: enum$] +// cdb-check: b : Suspend0 [Type: enum2$] // cdb-check: [+0x[...]] c : 6 [Type: int] // cdb-check: [+0x[...]] d : 7 [Type: int] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 5 [Type: int *] // cdb-command: g // cdb-command: dx b -// cdb-check: b : Suspend1 [Type: enum$] +// cdb-check: b : Suspend1 [Type: enum2$] // cdb-check: [+0x[...]] c : 7 [Type: int] // cdb-check: [+0x[...]] d : 8 [Type: int] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *] // cdb-command: g // cdb-command: dx b -// cdb-check: b : Returned [Type: enum$] +// cdb-check: b : Returned [Type: enum2$] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *] #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index b1ca5dfa1c77c..d27520c5cbaae 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -4,106 +4,105 @@ // cdb-command: g // cdb-command: dx a -// cdb-check:a : Some [Type: enum$ >] +// cdb-check:a : Some [Type: enum2$ >] // cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] // cdb-command: dx b -// cdb-check:b : None [Type: enum$ >] +// cdb-check:b : None [Type: enum2$ >] // cdb-command: dx c -// cdb-check:c : Tag1 [Type: enum$] +// cdb-check:c : Tag1 [Type: enum2$] // cdb-command: dx d -// cdb-check:d : Data [Type: enum$] +// cdb-check:d : Data [Type: enum2$] // cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] // cdb-command: dx e -// cdb-check:e : Tag2 [Type: enum$] +// cdb-check:e : Tag2 [Type: enum2$] // cdb-command: dx f -// cdb-check:f : Some [Type: enum$ > >] +// cdb-check:f : Some [Type: enum2$ > >] // cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] // cdb-command: dx g -// cdb-check:g : None [Type: enum$ > >] +// cdb-check:g : None [Type: enum2$ > >] // cdb-command: dx h -// cdb-check:h : Some [Type: enum$ >] +// cdb-check:h : Some [Type: enum2$ >] // cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] // cdb-command: dx i -// cdb-check:i : None [Type: enum$ >] +// cdb-check:i : None [Type: enum2$ >] // cdb-command: dx j // cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] // cdb-command: dx k -// cdb-check:k : Some [Type: enum$ >] +// cdb-check:k : Some [Type: enum2$ >] // cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] // cdb-command: dx l -// cdb-check:l : Ok [Type: enum$ > >] +// cdb-check:l : Ok [Type: enum2$ > >] // cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int] // cdb-command: dx niche128_some -// cdb-check:niche128_some : Some [Type: enum$ >] +// cdb-check: niche128_some : Some [Type: enum2$ >] // Note: we can't actually read the value of the field because CDB cannot handle 128 bit integers. // cdb-check: [+0x000] __0 [...] [Type: core::num::nonzero::NonZeroI128] // cdb-command: dx niche128_none -// cdb-check: niche128_none : None [Type: enum$ >] +// cdb-check: niche128_none : None [Type: enum2$ >] // cdb-command: dx niche_w_fields_1_some,d -// cdb-check: niche_w_fields_1_some,d : A [Type: enum$] +// cdb-check: niche_w_fields_1_some,d : A [Type: enum2$] // cdb-check: [+0x[...]] __0 : 0x[...] : 77 [Type: unsigned char *] // cdb-check: [+0x[...]] __1 : 7 [Type: unsigned int] // cdb-command: dx niche_w_fields_1_none,d -// cdb-check: niche_w_fields_1_none,d : B [Type: enum$] +// cdb-check: niche_w_fields_1_none,d : B [Type: enum2$] // cdb-check: [+0x[...]] __0 : 99 [Type: unsigned int] // cdb-command: dx niche_w_fields_2_some,d -// cdb-check: niche_w_fields_2_some,d : A [Type: enum$] -// cdb-check: [] [Type: enum$] +// cdb-check: niche_w_fields_2_some,d : A [Type: enum2$] // cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZeroU32] // cdb-check: [+0x[...]] __1 : 900 [Type: unsigned __int64] // cdb-command: dx niche_w_fields_2_none,d -// cdb-check: niche_w_fields_2_none,d : B [Type: enum$] +// cdb-check: niche_w_fields_2_none,d : B [Type: enum2$] // cdb-check: [+0x[...]] __0 : 1000 [Type: unsigned __int64] // cdb-command: dx niche_w_fields_3_some,d -// cdb-check: niche_w_fields_3_some,d : A [Type: enum$] +// cdb-check: niche_w_fields_3_some,d : A [Type: enum2$] // cdb-check: [+0x[...]] __0 : 137 [Type: unsigned char] // cdb-check: [+0x[...]] __1 : true [Type: bool] // cdb-command: dx niche_w_fields_3_niche1,d -// cdb-check: niche_w_fields_3_niche1,d : B [Type: enum$] +// cdb-check: niche_w_fields_3_niche1,d : B [Type: enum2$] // cdb-check: [+0x[...]] __0 : 12 [Type: unsigned char] // cdb-command: dx niche_w_fields_3_niche2,d -// cdb-check: niche_w_fields_3_niche2,d : C [Type: enum$] +// cdb-check: niche_w_fields_3_niche2,d : C [Type: enum2$] // cdb-check: [+0x[...]] __0 : false [Type: bool] // cdb-command: dx niche_w_fields_3_niche3,d -// cdb-check: niche_w_fields_3_niche3,d : D [Type: enum$] +// cdb-check: niche_w_fields_3_niche3,d : D [Type: enum2$] // cdb-check: [+0x[...]] __0 : 34 [Type: unsigned char] // cdb-command: dx niche_w_fields_3_niche4,d -// cdb-check: niche_w_fields_3_niche4,d : E [Type: enum$] +// cdb-check: niche_w_fields_3_niche4,d : E [Type: enum2$] // cdb-check: [+0x[...]] __0 : 56 [Type: unsigned char] // cdb-command: dx niche_w_fields_3_niche5,d -// cdb-check: niche_w_fields_3_niche5,d : F [Type: enum$] +// cdb-check: niche_w_fields_3_niche5,d : F [Type: enum2$] // cdb-command: dx -r3 niche_w_fields_std_result_ok,d -// cdb-check: niche_w_fields_std_result_ok,d : Ok [Type: enum$,alloc::alloc::Global>,u64> >] +// cdb-check: niche_w_fields_std_result_ok,d : Ok [Type: enum2$,alloc::alloc::Global>,u64> >] // cdb-check: [+0x[...]] __0 [Type: alloc::boxed::Box,alloc::alloc::Global>] // cdb-check: [+0x[...]] data_ptr : [...] // cdb-check: [+0x[...]] length : 3 [...] // cdb-command: dx -r3 niche_w_fields_std_result_err,d -// cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum$,alloc::alloc::Global>,u64> >] +// cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum2$,alloc::alloc::Global>,u64> >] // cdb-check: [+0x[...]] __0 : 789 [Type: unsigned __int64] use std::num::{NonZeroI128, NonZeroU32}; diff --git a/src/test/debuginfo/msvc-scalarpair-params.rs b/src/test/debuginfo/msvc-scalarpair-params.rs index 38a9633c9bfce..9630952cbaae0 100644 --- a/src/test/debuginfo/msvc-scalarpair-params.rs +++ b/src/test/debuginfo/msvc-scalarpair-params.rs @@ -18,10 +18,10 @@ // cdb-command: g // cdb-command: dx o1 -// cdb-check:o1 : Some [Type: enum$ >] +// cdb-check:o1 : Some [Type: enum2$ >] // cdb-check: [+0x004] __0 : 0x4d2 [Type: [...]] // cdb-command: dx o2 -// cdb-check:o2 : Some [Type: enum$ >] +// cdb-check:o2 : Some [Type: enum2$ >] // cdb-check: [+0x008] __0 : 0x162e [Type: unsigned __int64] // cdb-command: g diff --git a/src/test/debuginfo/mutex.rs b/src/test/debuginfo/mutex.rs index 00dccf5f9064a..e5b8ff1bcfd38 100644 --- a/src/test/debuginfo/mutex.rs +++ b/src/test/debuginfo/mutex.rs @@ -21,15 +21,14 @@ // // cdb-command:dx lock,d -// cdb-check:lock,d : Ok [Type: enum$,enum$ >, 0, 1, Poisoned> > >] +// cdb-check:lock,d : Ok [Type: enum2$,enum2$ >, 0, 1, Poisoned> > >] // cdb-check: [variant] : Ok // cdb-check: [...] __0 [Type: std::sync::mutex::MutexGuard] use std::sync::Mutex; #[allow(unused_variables)] -fn main() -{ +fn main() { let m = Mutex::new(0); let lock = m.try_lock(); zzz(); // #break diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index fe44c42aa5312..a51b37205e8aa 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -116,17 +116,17 @@ // cdb-check: [chars] : "IAMA OS string [...]" // cdb-command: dx some -// cdb-check:some : Some [Type: enum$ >] -// cdb-check: [] [Type: enum$ >] +// cdb-check:some : Some [Type: enum2$ >] +// cdb-check: [] [Type: enum2$ >] // cdb-check: [+0x002] __0 : 8 [Type: short] // cdb-command: dx none -// cdb-check:none : None [Type: enum$ >] -// cdb-check: [] [Type: enum$ >] +// cdb-check:none : None [Type: enum2$ >] +// cdb-check: [] [Type: enum2$ >] // cdb-command: dx some_string -// cdb-check:some_string : Some [Type: enum$ >] -// cdb-check: [] [Type: enum$ >] +// cdb-check:some_string : Some [Type: enum2$ >] +// cdb-check: [] [Type: enum2$ >] // cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] // cdb-command: dx linkedlist diff --git a/src/test/debuginfo/result-types.rs b/src/test/debuginfo/result-types.rs index c0d905a6acc4e..cdac47a784d94 100644 --- a/src/test/debuginfo/result-types.rs +++ b/src/test/debuginfo/result-types.rs @@ -7,15 +7,14 @@ // cdb-command: g // cdb-command: dx x,d -// cdb-check:x,d : Ok [Type: enum$ >] +// cdb-check:x,d : Ok [Type: enum2$ >] // cdb-check: [...] __0 : -3 [Type: int] // cdb-command: dx y -// cdb-check:y : Err [Type: enum$ >] +// cdb-check:y : Err [Type: enum2$ >] // cdb-check: [...] __0 : "Some error message" [Type: str] -fn main() -{ +fn main() { let x: Result = Ok(-3); assert_eq!(x.is_ok(), true); @@ -25,4 +24,6 @@ fn main() zzz(); // #break. } -fn zzz() { () } +fn zzz() { + () +} diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 426d9ddf2517b..9cc99d7767c1f 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -175,51 +175,51 @@ // 0-sized structs appear to be optimized away in some cases, so only check the structs that do // actually appear. // cdb-command:dv /t *_struct -// cdb-check:struct type_names::GenericStruct,f64> mut_generic_struct = [...] +// cdb-check:struct type_names::GenericStruct,f64> mut_generic_struct = [...] // ENUMS // cdb-command:dv /t *_enum_* -// cdb-check:union enum$ simple_enum_1 = [...] -// cdb-check:union enum$ simple_enum_2 = [...] -// cdb-check:union enum$ simple_enum_3 = [...] -// cdb-check:union enum$ > generic_enum_1 = [...] -// cdb-check:union enum$ > generic_enum_2 = [...] +// cdb-check:union enum2$ simple_enum_1 = [...] +// cdb-check:union enum2$ simple_enum_2 = [...] +// cdb-check:union enum2$ simple_enum_3 = [...] +// cdb-check:union enum2$ > generic_enum_1 = [...] +// cdb-check:union enum2$ > generic_enum_2 = [...] // TUPLES // cdb-command:dv /t tuple* -// cdb-check:struct tuple$ > > tuple1 = [...] -// cdb-check:struct tuple$,enum$,char> tuple2 = [...] +// cdb-check:struct tuple$ > > tuple1 = [...] +// cdb-check:struct tuple$,enum2$,char> tuple2 = [...] // BOX // cdb-command:dv /t box* // cdb-check:struct tuple$,i32> box1 = [...] -// cdb-check:struct tuple$ >,alloc::alloc::Global>,i32> box2 = [...] +// cdb-check:struct tuple$ >,alloc::alloc::Global>,i32> box2 = [...] // REFERENCES // cdb-command:dv /t *ref* // cdb-check:struct tuple$,i32> ref1 = [...] // cdb-check:struct tuple$ >,i32> ref2 = [...] // cdb-check:struct tuple$,i32> mut_ref1 = [...] -// cdb-check:struct tuple$,f64> >,i32> mut_ref2 = [...] +// cdb-check:struct tuple$,f64> >,i32> mut_ref2 = [...] // RAW POINTERS // cdb-command:dv /t *_ptr* // cdb-check:struct tuple$,isize> mut_ptr1 = [...] // cdb-check:struct tuple$,isize> mut_ptr2 = [...] -// cdb-check:struct tuple$ > >,isize> mut_ptr3 = [...] +// cdb-check:struct tuple$ > >,isize> mut_ptr3 = [...] // cdb-check:struct tuple$,isize> const_ptr1 = [...] // cdb-check:struct tuple$,isize> const_ptr2 = [...] -// cdb-check:struct tuple$ > >,isize> const_ptr3 = [...] +// cdb-check:struct tuple$ > >,isize> const_ptr3 = [...] // VECTORS // cdb-command:dv /t *vec* // cdb-check:struct tuple$,i16> fixed_size_vec1 = [...] // cdb-check:struct tuple$,i16> fixed_size_vec2 = [...] // cdb-check:struct alloc::vec::Vec vec1 = [...] -// cdb-check:struct alloc::vec::Vec,alloc::alloc::Global> vec2 = [...] +// cdb-check:struct alloc::vec::Vec,alloc::alloc::Global> vec2 = [...] // cdb-command:dv /t slice* // cdb-check:struct slice$ slice1 = [...] -// cdb-check:struct slice$ > slice2 = [...] +// cdb-check:struct slice$ > slice2 = [...] // TRAITS // cdb-command:dv /t *_trait @@ -238,16 +238,16 @@ // cdb-check:struct tuple$),usize> unsafe_fn_with_return_value = [...] // cdb-check:struct tuple$ extern_c_fn_with_return_value = [...] // cdb-check:struct tuple$ rust_fn_with_return_value = [...] -// cdb-check:struct tuple$ >),usize> unsafe_fn = [...] +// cdb-check:struct tuple$ >),usize> unsafe_fn = [...] // cdb-check:struct tuple$ extern_c_fn = [...] -// cdb-check:struct tuple$ >,enum$ > >),usize> rust_fn = [...] +// cdb-check:struct tuple$ >,enum2$ > >),usize> rust_fn = [...] // cdb-command:dv /t *_function* // cdb-check:struct tuple$, ...),usize> variadic_function = [...] // cdb-check:struct tuple$ generic_function_struct3 = [...] // cdb-check:struct tuple$ generic_function_int = [...] // cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("rust_fn") // cdb-check:Return Type: void -// cdb-check:Parameter Types: enum$ >,enum$ > > +// cdb-check:Parameter Types: enum2$ >,enum2$ > > // cdb-command:dx Debugger.State.Scripts.@"type-names.cdb".Contents.getFunctionDetails("rust_fn_with_return_value") // cdb-check:Return Type: usize // cdb-check:Parameter Types: f64 From 725ceae45531b70eb55219272de20f4262b43cad Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 7 Jul 2022 15:04:23 +0200 Subject: [PATCH 03/15] Support wrapping 128-bit tag ranges for cpp-like enum debuginfo. --- src/etc/natvis/intrinsic.natvis | 6 +++-- src/test/debuginfo/msvc-pretty-enums.rs | 32 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 82f47b7814e04..bf5c006c4de43 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -1,4 +1,4 @@ - + {(char*)data_ptr,[length]s8} @@ -179,7 +179,9 @@ - + diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index d27520c5cbaae..10b16c2f89783 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -53,6 +53,18 @@ // cdb-command: dx niche128_none // cdb-check: niche128_none : None [Type: enum2$ >] +// cdb-command: dx wrapping_niche128_dataful +// cdb-check: wrapping_niche128_dataful : X [Type: enum2$] +// cdb-check: [+0x000] __0 [Type: msvc_pretty_enums::Wrapping128] + +// cdb-command: dx wrapping_niche128_none1 +// cdb-check: wrapping_niche128_none1 : Y [Type: enum2$] +// cdb-check: [+0x000] __0 [Type: msvc_pretty_enums::Wrapping128] + +// cdb-command: dx wrapping_niche128_none2 +// cdb-check: wrapping_niche128_none2 : Z [Type: enum2$] +// cdb-check: [+0x000] __0 [Type: msvc_pretty_enums::Wrapping128] + // cdb-command: dx niche_w_fields_1_some,d // cdb-check: niche_w_fields_1_some,d : A [Type: enum2$] // cdb-check: [+0x[...]] __0 : 0x[...] : 77 [Type: unsigned char *] @@ -64,6 +76,7 @@ // cdb-command: dx niche_w_fields_2_some,d // cdb-check: niche_w_fields_2_some,d : A [Type: enum2$] +// cdb-check: [] [Type: enum2$] // cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZeroU32] // cdb-check: [+0x[...]] __1 : 900 [Type: unsigned __int64] @@ -105,6 +118,8 @@ // cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum2$,alloc::alloc::Global>,u64> >] // cdb-check: [+0x[...]] __0 : 789 [Type: unsigned __int64] +#![feature(rustc_attrs)] + use std::num::{NonZeroI128, NonZeroU32}; pub enum CStyleEnum { @@ -141,6 +156,18 @@ enum NicheLayoutWithFields3 { F, } +#[rustc_layout_scalar_valid_range_start(340282366920938463463374607431768211454)] +#[rustc_layout_scalar_valid_range_end(1)] +#[repr(transparent)] +struct Wrapping128(u128); + +// #[rustc_layout(debug)] +enum Wrapping128Niche { + X(Wrapping128), + Y, + Z, +} + fn main() { let a = Some(CStyleEnum::Low); let b = Option::::None; @@ -157,6 +184,11 @@ fn main() { let niche128_some = Some(NonZeroI128::new(123456).unwrap()); let niche128_none: Option = None; + let wrapping_niche128_dataful = + unsafe { Wrapping128Niche::X(Wrapping128(340282366920938463463374607431768211454)) }; + let wrapping_niche128_none1 = Wrapping128Niche::Y; + let wrapping_niche128_none2 = Wrapping128Niche::Z; + let niche_w_fields_1_some = NicheLayoutWithFields1::A(&77, 7); let niche_w_fields_1_none = NicheLayoutWithFields1::B(99); From 6875f1272f5ce66a63d58c112a5903a9dfb0c994 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 7 Jul 2022 15:04:56 +0200 Subject: [PATCH 04/15] Remove out-dated NatVis visualizer. --- src/etc/natvis/liballoc.natvis | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index 912418fa7d1eb..bf6c02b91461a 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -185,12 +185,4 @@ - - - Borrowed({__0}) - Owned({__0}) - - __0 - - From 1bbda887fff26aebf322564a64070e7fdeefc452 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 7 Jul 2022 17:20:45 +0200 Subject: [PATCH 05/15] intrinsic.natvis: Don't access fields from context object in . WinDbg supports that but Visual Studio doesn't. Pass the value as a parameter instead. --- src/etc/natvis/intrinsic.natvis | 77 ++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index bf5c006c4de43..9d18de3f0099a 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -156,11 +156,14 @@ --> + + + @@ -182,6 +185,8 @@ + + @@ -205,27 +210,27 @@ {variant14.NAME,en} {variant15.NAME,en} - {variant_fallback.NAME,en} + {variant_fallback.NAME,en} - {variant0.NAME,en} - {variant1.NAME,en} - {variant2.NAME,en} - {variant3.NAME,en} - {variant4.NAME,en} - {variant5.NAME,en} - {variant6.NAME,en} - {variant7.NAME,en} - {variant8.NAME,en} - {variant9.NAME,en} - {variant10.NAME,en} - {variant11.NAME,en} - {variant12.NAME,en} - {variant13.NAME,en} - {variant14.NAME,en} - {variant15.NAME,en} + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} {variant_fallback.NAME,en} @@ -246,27 +251,27 @@ variant14.value variant15.value - variant_fallback.value + variant_fallback.value - variant0.value - variant1.value - variant2.value - variant3.value - variant4.value - variant5.value - variant6.value - variant7.value - variant8.value - variant9.value - variant10.value - variant11.value - variant12.value - variant13.value - variant14.value - variant15.value + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value variant_fallback.value From 3a72ea05a063453eeed10f0aa942c4bc669019d5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 7 Jul 2022 17:22:04 +0200 Subject: [PATCH 06/15] [debuginfo] Add more test cases cpp-like enum debuginfo. --- src/test/debuginfo/msvc-pretty-enums.rs | 43 ++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index 10b16c2f89783..03fc96cd53dde 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -55,15 +55,23 @@ // cdb-command: dx wrapping_niche128_dataful // cdb-check: wrapping_niche128_dataful : X [Type: enum2$] -// cdb-check: [+0x000] __0 [Type: msvc_pretty_enums::Wrapping128] +// cdb-check: [+0x[...]] __0 [Type: msvc_pretty_enums::Wrapping128] // cdb-command: dx wrapping_niche128_none1 // cdb-check: wrapping_niche128_none1 : Y [Type: enum2$] -// cdb-check: [+0x000] __0 [Type: msvc_pretty_enums::Wrapping128] +// cdb-check: [+0x[...]] __0 [Type: msvc_pretty_enums::Wrapping128] // cdb-command: dx wrapping_niche128_none2 // cdb-check: wrapping_niche128_none2 : Z [Type: enum2$] -// cdb-check: [+0x000] __0 [Type: msvc_pretty_enums::Wrapping128] +// cdb-check: [+0x[...]] __0 [Type: msvc_pretty_enums::Wrapping128] + +// cdb-command: dx direct_tag_128_a,d +// cdb-check: direct_tag_128_a,d : A [Type: enum2$] +// cdb-check: [+0x[...]] __0 : 42 [Type: unsigned int] + +// cdb-command: dx direct_tag_128_b,d +// cdb-check: direct_tag_128_b,d : B [Type: enum2$] +// cdb-check: [+0x[...]] __0 : 137 [Type: unsigned int] // cdb-command: dx niche_w_fields_1_some,d // cdb-check: niche_w_fields_1_some,d : A [Type: enum2$] @@ -76,7 +84,6 @@ // cdb-command: dx niche_w_fields_2_some,d // cdb-check: niche_w_fields_2_some,d : A [Type: enum2$] -// cdb-check: [] [Type: enum2$] // cdb-check: [+0x[...]] __0 : 800 [Type: core::num::nonzero::NonZeroU32] // cdb-check: [+0x[...]] __1 : 900 [Type: unsigned __int64] @@ -118,7 +125,17 @@ // cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum2$,alloc::alloc::Global>,u64> >] // cdb-check: [+0x[...]] __0 : 789 [Type: unsigned __int64] +// cdb-command: dx -r2 arbitrary_discr1,d +// cdb-check: arbitrary_discr1,d : Abc [Type: enum2$] +// cdb-check: [+0x[...]] __0 : 1234 [Type: unsigned int] + +// cdb-command: dx -r2 arbitrary_discr2,d +// cdb-check: arbitrary_discr2,d : Def [Type: enum2$] +// cdb-check: [+0x[...]] __0 : 5678 [Type: unsigned int] + #![feature(rustc_attrs)] +#![feature(repr128)] +#![feature(arbitrary_enum_discriminant)] use std::num::{NonZeroI128, NonZeroU32}; @@ -168,6 +185,18 @@ enum Wrapping128Niche { Z, } +#[repr(i128)] +enum DirectTag128 { + A(u32), + B(u32), +} + +#[repr(u32)] +enum ArbitraryDiscr { + Abc(u32) = 1000, + Def(u32) = 5000_000, +} + fn main() { let a = Some(CStyleEnum::Low); let b = Option::::None; @@ -189,6 +218,9 @@ fn main() { let wrapping_niche128_none1 = Wrapping128Niche::Y; let wrapping_niche128_none2 = Wrapping128Niche::Z; + let direct_tag_128_a = DirectTag128::A(42); + let direct_tag_128_b = DirectTag128::B(137); + let niche_w_fields_1_some = NicheLayoutWithFields1::A(&77, 7); let niche_w_fields_1_none = NicheLayoutWithFields1::B(99); @@ -205,6 +237,9 @@ fn main() { let niche_w_fields_std_result_ok: Result, u64> = Ok(vec![1, 2, 3].into()); let niche_w_fields_std_result_err: Result, u64> = Err(789); + let arbitrary_discr1 = ArbitraryDiscr::Abc(1234); + let arbitrary_discr2 = ArbitraryDiscr::Def(5678); + zzz(); // #break } From 8ef030183334bdcd7f4316c2efdc59a9e916546d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 8 Jul 2022 11:44:25 +0200 Subject: [PATCH 07/15] intrinsic.natvis: Add comments, make names more consistent. --- src/etc/natvis/intrinsic.natvis | 92 +++++++++++++++++---------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 9d18de3f0099a..a2489b463b78e 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -155,17 +155,19 @@ See `compiler\rustc_codegen_llvm\src\debuginfo\metadata\enums\cpp_like.rs` for more information. --> - - - + + + + - - - - - + + + + + @@ -182,11 +184,13 @@ + - - + (lt_or_eq128(begin_hi, begin_lo, x_hi, x_lo) && lt_or_eq128(x_hi, x_lo, end_hi, end_lo)) : + (lt_or_eq128(begin_hi, begin_lo, x_hi, x_lo) || lt_or_eq128(x_hi, x_lo, end_hi, end_lo))"> + + @@ -212,22 +216,22 @@ {variant_fallback.NAME,en} - {variant0.NAME,en} - {variant1.NAME,en} - {variant2.NAME,en} - {variant3.NAME,en} - {variant4.NAME,en} - {variant5.NAME,en} - {variant6.NAME,en} - {variant7.NAME,en} - {variant8.NAME,en} - {variant9.NAME,en} - {variant10.NAME,en} - {variant11.NAME,en} - {variant12.NAME,en} - {variant13.NAME,en} - {variant14.NAME,en} - {variant15.NAME,en} + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} variant_fallback.value - variant0.value - variant1.value - variant2.value - variant3.value - variant4.value - variant5.value - variant6.value - variant7.value - variant8.value - variant9.value - variant10.value - variant11.value - variant12.value - variant13.value - variant14.value - variant15.value + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value Date: Fri, 8 Jul 2022 11:46:39 +0200 Subject: [PATCH 08/15] [compiletest] Add compiler-bundled NatVis files to test input stamp. --- src/tools/compiletest/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index ac6d80bb439b3..0e2cc52a645bc 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -545,6 +545,8 @@ fn common_inputs_stamp(config: &Config) -> Stamp { stamp.add_path(&path); } + stamp.add_dir(&rust_src_dir.join("src/etc/natvis")); + stamp.add_dir(&config.run_lib_path); if let Some(ref rustdoc_path) = config.rustdoc_path { From 8433e2a66fad920e1312c02dc4395ceed98a2705 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 8 Jul 2022 17:09:32 +0200 Subject: [PATCH 09/15] [debuginfo] Remove the notion of a 'fallback variant' from the CPP-like enum debuginfo encoding. --- .../src/debuginfo/metadata/enums/cpp_like.rs | 88 +++++++++++++++---- src/etc/natvis/intrinsic.natvis | 76 +++++++++++++--- 2 files changed, 135 insertions(+), 29 deletions(-) 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 7a32e2550433d..c88dfed7e47ef 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 @@ -105,14 +105,6 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// that case. Both `DISCR_BEGIN` and `DISCR_END` are inclusive bounds. /// Note that these ranges can wrap around, so that `DISCR_END < DISCR_BEGIN`. /// -/// The field in the top-level union that corresponds to the dataful variant -/// is called `variant_fallback` instead of `variant`. This is mainly -/// an optimization that enables a shorter NatVis definition. That way we -/// only need to specify a `tag == variantX.DISCR_EXACT` entry for the indexed -/// variants. Otherwise we'd need to have that and then an additional entry -/// checking `in_range(variantX.DISCR_BEGIN, variantX.DISCR_END)` for each -/// index. -/// /// Single-variant enums don't actually have a tag field. In this case we /// emit a static tag field (that always has the value 0) so we can use the /// same representation (and NatVis). @@ -123,6 +115,72 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// Instead of the `tag` field, we generate two fields `tag128_lo` and `tag128_hi`, /// Instead of `DISCR_EXACT`, we generate `DISCR128_EXACT_LO` and `DISCR128_EXACT_HI`, /// and so on. +/// +/// +/// The following pseudocode shows how to decode an enum value in a debugger: +/// +/// ```ignore +/// +/// fn find_active_variant(enum_value) -> (VariantName, VariantValue) { +/// let is_128_bit = enum_value.has_field("tag128_lo"); +/// +/// if !is_128_bit { +/// // Note: `tag` can be a static field for enums with only one +/// // inhabited variant. +/// let tag = enum_value.field("tag").value; +/// +/// // For each variant, check if it is a match. Only one of them will match, +/// // so if we find it we can return it immediately. +/// for variant_field in enum_value.fields().filter(|f| f.name.starts_with("variant")) { +/// if variant_field.has_field("DISCR_EXACT") { +/// // This variant corresponds to a single tag value +/// if variant_field.field("DISCR_EXACT").value == tag { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } else { +/// // This is a range variant +/// let begin = variant_field.field("DISCR_BEGIN"); +/// let end = variant_field.field("DISCR_END"); +/// +/// if tag >= begin && tag <= end { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } +/// } +/// } else { +/// // Basically the same as with smaller tags, we just have to +/// // stitch the values together. +/// let tag: u128 = (enum_value.field("tag128_lo").value as u128) | +/// (enum_value.field("tag128_hi").value as u128 << 64); +/// +/// for variant_field in enum_value.fields().filter(|f| f.name.starts_with("variant")) { +/// if variant_field.has_field("DISCR128_EXACT_LO") { +/// let discr_exact = (variant_field.field("DISCR128_EXACT_LO" as u128) | +/// (variant_field.field("DISCR128_EXACT_HI") as u128 << 64); +/// +/// // This variant corresponds to a single tag value +/// if discr_exact.value == tag { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } else { +/// // This is a range variant +/// let begin = (variant_field.field("DISCR128_BEGIN_LO").value as u128) | +/// (variant_field.field("DISCR128_BEGIN_HI").value as u128 << 64); +/// let end = (variant_field.field("DISCR128_END_LO").value as u128) | +/// (variant_field.field("DISCR128_END_HI").value as u128 << 64); +/// +/// if tag >= begin && tag <= end { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } +/// } +/// } +/// +/// // We should have found an active variant at this point. +/// unreachable!(); +/// } +/// +/// ``` pub(super) fn build_enum_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, @@ -290,7 +348,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>( build_field_di_node( cx, enum_type_di_node, - &variant_union_field_name(variant_index, None), + &variant_union_field_name(variant_index), // NOTE: We use the size and align of the entire type, not from variant_layout // since the later is sometimes smaller (if it has fewer fields). size_and_align_of(enum_type_and_layout), @@ -691,8 +749,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( .source_info .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)); - let field_name = - variant_union_field_name(variant_member_info.variant_index, dataful_variant_index); + let field_name = variant_union_field_name(variant_member_info.variant_index); let (size, align) = size_and_align_of(enum_type_and_layout); let variant_struct_type_wrapper = build_variant_struct_wrapper_type_di_node( @@ -795,10 +852,7 @@ struct VariantFieldInfo<'ll> { discr: DiscrResult, } -fn variant_union_field_name( - variant_index: VariantIdx, - dataful_variant_index: Option, -) -> Cow<'static, str> { +fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> { const PRE_ALLOCATED: [&str; 16] = [ "variant0", "variant1", @@ -818,10 +872,6 @@ fn variant_union_field_name( "variant15", ]; - if Some(variant_index) == dataful_variant_index { - return Cow::from("variant_fallback"); - } - PRE_ALLOCATED .get(variant_index.as_usize()) .map(|&s| Cow::from(s)) diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index a2489b463b78e..277e57aaf6fc5 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -157,7 +157,7 @@ - + @@ -186,7 +186,7 @@ - @@ -214,7 +214,22 @@ {variant14.NAME,en} {variant15.NAME,en} - {variant_fallback.NAME,en} + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} {variant0.NAME,en} {variant1.NAME,en} @@ -233,9 +248,22 @@ {variant14.NAME,en} {variant15.NAME,en} - {variant_fallback.NAME,en} + {variant0.NAME,en} + {variant1.NAME,en} + {variant2.NAME,en} + {variant3.NAME,en} + {variant4.NAME,en} + {variant5.NAME,en} + {variant6.NAME,en} + {variant7.NAME,en} + {variant8.NAME,en} + {variant9.NAME,en} + {variant10.NAME,en} + {variant11.NAME,en} + {variant12.NAME,en} + {variant13.NAME,en} + {variant14.NAME,en} + {variant15.NAME,en} variant0.value @@ -255,7 +283,22 @@ variant14.value variant15.value - variant_fallback.value + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value variant0.value variant1.value @@ -274,9 +317,22 @@ variant14.value variant15.value - variant_fallback.value + variant0.value + variant1.value + variant2.value + variant3.value + variant4.value + variant5.value + variant6.value + variant7.value + variant8.value + variant9.value + variant10.value + variant11.value + variant12.value + variant13.value + variant14.value + variant15.value From 171d8a3f57b00ff9d213c74729c5ff228b016c8c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 8 Jul 2022 17:15:43 +0200 Subject: [PATCH 10/15] [debuginfo] Don't mark fields and types as artificial in CPP-like enum debuginfo encoding. LLDB historically has had problems with "artificial" entries and there is no real benefit to emitting that flag. --- .../src/debuginfo/metadata/enums/cpp_like.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 c88dfed7e47ef..410cfbc2de8ca 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 @@ -119,7 +119,7 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// /// The following pseudocode shows how to decode an enum value in a debugger: /// -/// ```ignore +/// ```text /// /// fn find_active_variant(enum_value) -> (VariantName, VariantValue) { /// let is_128_bit = enum_value.has_field("tag128_lo"); @@ -365,7 +365,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>( unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, variant_names_type_di_node, - DIFlags::FlagArtificial, + DIFlags::FlagZero, Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)), tag_base_type_align.bits() as u32, ) @@ -482,7 +482,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( // NOTE: We use size and align of enum_type, not from variant_layout: size_and_align_of(enum_or_generator_type_and_layout), Some(enum_or_generator_type_di_node), - DIFlags::FlagArtificial, + DIFlags::FlagZero, ), |cx, wrapper_struct_type_di_node| { enum DiscrKind { @@ -526,7 +526,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( "value", size_and_align_of(enum_or_generator_type_and_layout), Size::ZERO, - DIFlags::FlagArtificial, + DIFlags::FlagZero, variant_struct_type_di_node, )); @@ -540,7 +540,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, type_di_node, - DIFlags::FlagArtificial, + DIFlags::FlagZero, Some(cx.const_u64(value)), align.bits() as u32, ) From 95d75914788aaae88930701f3c419257adbf8288 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 20 Jul 2022 16:15:02 +0200 Subject: [PATCH 11/15] [debuginfo] Update cpp-like enum decoding docs to account for wrapping tag ranges. --- .../src/debuginfo/metadata/enums/cpp_like.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 410cfbc2de8ca..e3951c8d0f963 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 @@ -142,7 +142,7 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// let begin = variant_field.field("DISCR_BEGIN"); /// let end = variant_field.field("DISCR_END"); /// -/// if tag >= begin && tag <= end { +/// if is_in_range(tag, begin, end) { /// return (variant_field.field("NAME"), variant_field.value); /// } /// } @@ -169,7 +169,7 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// let end = (variant_field.field("DISCR128_END_LO").value as u128) | /// (variant_field.field("DISCR128_END_HI").value as u128 << 64); /// -/// if tag >= begin && tag <= end { +/// if is_in_range(tag, begin, end) { /// return (variant_field.field("NAME"), variant_field.value); /// } /// } @@ -180,6 +180,16 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// unreachable!(); /// } /// +/// // Check if a value is within the given range +/// // (where the range might wrap around the value space) +/// fn is_in_range(value, start, end) -> bool { +/// if start < end { +/// value >= start && value <= end +/// } else { +/// value >= start || value <= end +/// } +/// } +/// /// ``` pub(super) fn build_enum_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, From b0e3ed6e8dc6782ae86707e2332a9d42a44935d6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 11 Aug 2022 11:09:24 +0200 Subject: [PATCH 12/15] [debuginfo] Use IndexMap instead of FxHashMap while generating cpp-like generator debuginfo. --- .../src/debuginfo/metadata/enums/cpp_like.rs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) 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 e3951c8d0f963..daec9303b2c67 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 @@ -5,7 +5,8 @@ use rustc_codegen_ssa::{ debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo}, traits::ConstMethods, }; -use rustc_data_structures::fx::FxHashMap; + +use rustc_index::vec::IndexVec; use rustc_middle::{ bug, ty::{ @@ -680,6 +681,7 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( let common_upvar_names = closure_saved_names_of_captured_variables(cx.tcx, generator_def_id); let variant_range = generator_substs.variant_range(generator_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, generator_type_and_layout); @@ -691,10 +693,17 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( .map(|variant_index| (variant_index, GeneratorSubsts::variant_name(variant_index))), ); - let discriminants: FxHashMap = generator_substs - .discriminants(generator_def_id, cx.tcx) - .map(|(variant_index, discr)| (variant_index, DiscrResult::Value(discr.val))) - .collect(); + let discriminants: IndexVec = { + let discriminants_iter = generator_substs.discriminants(generator_def_id, cx.tcx); + let mut discriminants: IndexVec = + IndexVec::with_capacity(variant_count); + for (variant_index, discr) in discriminants_iter { + // Assert that the index in the IndexMap matches up with the given VariantIdx. + assert_eq!(variant_index, discriminants.next_index()); + discriminants.push(DiscrResult::Value(discr.val)); + } + discriminants + }; // Build the type node for each field. let variant_field_infos: SmallVec> = variant_range @@ -721,7 +730,7 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>( variant_index, variant_struct_type_di_node, source_info, - discr: discriminants[&variant_index], + discr: discriminants[variant_index], } }) .collect(); From ee634fbf0d754df41b875f9f67088ad406efa96c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 12 Aug 2022 12:00:02 +0200 Subject: [PATCH 13/15] [debuginfo] Update codegen tests for new cpp-like enum debuginfo encoding. --- src/test/codegen/async-fn-debug-awaitee-field.rs | 4 ++-- src/test/codegen/async-fn-debug-msvc.rs | 7 ++++--- src/test/codegen/debug-vtable.rs | 2 +- src/test/codegen/generator-debug-msvc.rs | 8 +++++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/test/codegen/async-fn-debug-awaitee-field.rs b/src/test/codegen/async-fn-debug-awaitee-field.rs index efb345fa9f3e5..909cd0062a623 100644 --- a/src/test/codegen/async-fn-debug-awaitee-field.rs +++ b/src/test/codegen/async-fn-debug-awaitee-field.rs @@ -12,11 +12,11 @@ async fn async_fn_test() { } // NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", -// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum$", +// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", // CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]], // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]], // NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "GenFuture", -// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "GenFuture >", +// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "GenFuture >", fn main() { let _fn = async_fn_test(); diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index 8995605e3dd72..73c652c9dd15e 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -16,7 +16,7 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum$", +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, @@ -36,16 +36,17 @@ async fn async_fn_test() { // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 14, -// CHECK-SAME: baseType: [[VARIANT:![0-9]*]] +// CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: [[VARIANT_WRAPPER]], file: !2, baseType: [[VARIANT:![0-9]*]], // CHECK: [[VARIANT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[VARIANT]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "discriminant", scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "tag", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial fn main() { diff --git a/src/test/codegen/debug-vtable.rs b/src/test/codegen/debug-vtable.rs index b9cb4f93d07d8..bdd312878ec88 100644 --- a/src/test/codegen/debug-vtable.rs +++ b/src/test/codegen/debug-vtable.rs @@ -46,7 +46,7 @@ // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) // NONMSVC: !DIGlobalVariable(name: ">)>>::{vtable}" -// MSVC: !DIGlobalVariable(name: "impl$,assoc$ > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$" +// MSVC: !DIGlobalVariable(name: "impl$,assoc$ > > > > > > > > >::vtable$" // NONMSVC: !DIGlobalVariable(name: " as core::ops::function::FnOnce<()>>::{vtable}" // MSVC: !DIGlobalVariable(name: "impl$, core::ops::function::FnOnce > >::vtable$ diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index 033da80be16cc..b712068bf27f2 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -20,7 +20,7 @@ fn generator_test() -> impl Generator { // FIXME: No way to reliably check the filename. -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum$" +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$" // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14, @@ -40,16 +40,18 @@ fn generator_test() -> impl Generator { // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 17, -// CHECK-SAME: baseType: [[VARIANT:![0-9]*]] +// CHECK-SAME: baseType: [[VARIANT_WRAPPER:![0-9]*]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) +// CHECK: [[VARIANT_WRAPPER]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Variant4", scope: [[GEN]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "value", scope: [[VARIANT_WRAPPER]], {{.*}}, baseType: [[VARIANT:![0-9]*]], // CHECK: [[VARIANT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[VARIANT]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "discriminant", scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "tag", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial fn main() { From 6d030a51dd40541b3ae80f6b0278e2026c56b95a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 12 Aug 2022 17:16:55 +0200 Subject: [PATCH 14/15] [debuginfo] Update src/test/debuginfo/mutex.rs for new cpp-like enum debuginfo encoding. --- src/test/debuginfo/mutex.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/test/debuginfo/mutex.rs b/src/test/debuginfo/mutex.rs index e5b8ff1bcfd38..314ba40b0e3d0 100644 --- a/src/test/debuginfo/mutex.rs +++ b/src/test/debuginfo/mutex.rs @@ -20,18 +20,20 @@ // cdb-check: [] [Type: core::cell::UnsafeCell] // -// cdb-command:dx lock,d -// cdb-check:lock,d : Ok [Type: enum2$,enum2$ >, 0, 1, Poisoned> > >] -// cdb-check: [variant] : Ok +// cdb-command:dx _lock,d +// cdb-check:_lock,d : Ok [Type: enum2$,enum2$ > > > >] // cdb-check: [...] __0 [Type: std::sync::mutex::MutexGuard] use std::sync::Mutex; -#[allow(unused_variables)] fn main() { let m = Mutex::new(0); - let lock = m.try_lock(); + let _lock = m.try_lock(); + + println!("this line avoids an `Ambiguous symbol error` while setting the breakpoint"); + zzz(); // #break } +#[inline(never)] fn zzz() {} From 03b93d008d16132dc644d811bef9e452c515ed75 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 15 Aug 2022 10:50:09 +0200 Subject: [PATCH 15/15] [debuginfo] Fix msvc-pretty-enums debuginfo test for i686. --- src/test/debuginfo/msvc-pretty-enums.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index 03fc96cd53dde..45d5ddf5c0ebc 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -160,8 +160,8 @@ enum NicheLayoutWithFields1<'a> { } enum NicheLayoutWithFields2 { - A(NonZeroU32, usize), - B(usize), + A(NonZeroU32, u64), + B(u64), } enum NicheLayoutWithFields3 {