From 622da5d834e862112e860db1fc0404bd8604f578 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 20 Jun 2022 17:50:27 +0200 Subject: debuginfo: Change C++-like encoding for enums. The updated encoding should be able to handle niche layouts where more than one variant has fields. --- .../rustc_codegen_llvm/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 + 6 files changed, 583 insertions(+), 202 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index bd84100e0e8..25a989bdf05 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 d6e2c8ccdf4..55bdd29d67c 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 73e01d0453b..9b3d080bfd6 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 f1935e0ec31..dae90a43f26 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 ce2f419c4ac..e30622cbdce 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 3139f93bfef..89611fc0dee 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, -- cgit 1.4.1-3-g733a5 From 063ebfa5707015f895fc50c3a1dd70ab6867bc9b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 7 Jul 2022 15:01:43 +0200 Subject: 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 +++++++++--- .../rustc_codegen_ssa/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(-) (limited to 'compiler/rustc_codegen_llvm/src') 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 55bdd29d67c..7a32e255043 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 1dde6ae8edf..135ed680da2 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 9f1aa525d1f..82f47b7814e 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 95b0819cc38..11c4ae2f659 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 b1ca5dfa1c7..d27520c5cba 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 38a9633c9bf..9630952cbaa 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 00dccf5f906..e5b8ff1bcfd 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 fe44c42aa53..a51b37205e8 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 c0d905a6acc..cdac47a784d 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 426d9ddf251..9cc99d7767c 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 -- cgit 1.4.1-3-g733a5 From 8433e2a66fad920e1312c02dc4395ceed98a2705 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 8 Jul 2022 17:09:32 +0200 Subject: [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(-) (limited to 'compiler/rustc_codegen_llvm/src') 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 7a32e255043..c88dfed7e47 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 a2489b463b7..277e57aaf6f 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 -- cgit 1.4.1-3-g733a5 From 171d8a3f57b00ff9d213c74729c5ff228b016c8c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 8 Jul 2022 17:15:43 +0200 Subject: [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(-) (limited to 'compiler/rustc_codegen_llvm/src') 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 c88dfed7e47..410cfbc2de8 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, ) -- cgit 1.4.1-3-g733a5 From 95d75914788aaae88930701f3c419257adbf8288 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 20 Jul 2022 16:15:02 +0200 Subject: [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(-) (limited to 'compiler/rustc_codegen_llvm/src') 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 410cfbc2de8..e3951c8d0f9 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>, -- cgit 1.4.1-3-g733a5 From b0e3ed6e8dc6782ae86707e2332a9d42a44935d6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 11 Aug 2022 11:09:24 +0200 Subject: [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(-) (limited to 'compiler/rustc_codegen_llvm/src') 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 e3951c8d0f9..daec9303b2c 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(); -- cgit 1.4.1-3-g733a5