diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index bd84100e0e88..25a989bdf052 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 d6e2c8ccdf44..daec9303b2c6 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,21 @@ 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_index::vec::IndexVec; 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 +23,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 +37,161 @@ 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} { -/// +/// union enum2$<{fully-qualified-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. +/// 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. /// -/// At the LLVM IR level this looks like +/// 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`. /// -/// ```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) -/// ``` +/// 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). /// -/// 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: +/// 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. /// -/// ```c -/// union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> { -/// struct { -/// -/// } dataful_variant; -/// enum Discriminant$ { -/// -/// } discriminant; +/// +/// The following pseudocode shows how to decode an enum value in a debugger: +/// +/// ```text +/// +/// 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 is_in_range(tag, begin, 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 is_in_range(tag, begin, end) { +/// return (variant_field.field("NAME"), variant_field.value); +/// } +/// } +/// } +/// } +/// +/// // We should have found an active variant at this point. +/// unreachable!(); /// } -/// ``` /// -/// 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. +/// // 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>, unique_type_id: UniqueTypeId<'tcx>, @@ -135,27 +239,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 +322,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), + // 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::FlagZero, + 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), + 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::FlagZero, - discr_type_di_node, ), - ] + |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::FlagZero, + 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::FlagZero, + 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>( @@ -369,6 +681,29 @@ 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); + + 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: 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 @@ -391,29 +726,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 +755,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 ... @@ -438,6 +771,19 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( 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( + 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 +802,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 +812,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,6 +868,7 @@ 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> { @@ -512,3 +896,29 @@ fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> { .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 73e01d0453b2..9b3d080bfd6a 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 f1935e0ec31a..dae90a43f265 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 ce2f419c4acd..e30622cbdced 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 3139f93bfefa..89611fc0dee1 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 8cd5a0fc2475..135ed680da2d 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); @@ -391,11 +389,10 @@ 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( - 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$<"); + output.push_str("enum2$<"); 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 30ff364210da..4172ce3bb306 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 5f5b5de790e4..f9bffe6d8239 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 558536fa613a..277e57aaf6fc 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,189 @@ - - - - {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} + + {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} + + {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 + 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 + + 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 diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index 912418fa7d1e..bf6c02b91461 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -185,12 +185,4 @@ - - - Borrowed({__0}) - Owned({__0}) - - __0 - - diff --git a/src/test/codegen/async-fn-debug-awaitee-field.rs b/src/test/codegen/async-fn-debug-awaitee-field.rs index efb345fa9f3e..909cd0062a62 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 8995605e3dd7..73c652c9dd15 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 b9cb4f93d07d..bdd312878ec8 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 033da80be16c..b712068bf27f 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() { diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs index d6d7e5b44aaf..11c4ae2f6592 100644 --- a/src/test/debuginfo/generator-objects.rs +++ b/src/test/debuginfo/generator-objects.rs @@ -41,31 +41,26 @@ // cdb-command: g // cdb-command: dx b -// cdb-check: b : Unresumed [Type: enum$] -// cdb-check: [variant] : Unresumed +// 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: [variant] : Suspend0 +// 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: [variant] : Suspend1 +// 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: [] [Type: enum$] -// cdb-check: [variant] : Returned +// 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 a153a9a42289..45d5ddf5c0eb 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -4,69 +4,141 @@ // 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: enum2$ >] // 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: enum2$ >] // cdb-command: dx c -// cdb-check:c : Tag1 [Type: enum$] -// cdb-check: [] [Type: enum$] -// cdb-check: [variant] : Tag1 +// cdb-check:c : Tag1 [Type: enum2$] // cdb-command: dx d -// cdb-check:d : Data({...}) [Type: enum$] -// cdb-check: [] [Type: enum$] -// cdb-check: [variant] : Data +// 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: [] [Type: enum$] -// cdb-check: [variant] : Tag2 +// cdb-check:e : Tag2 [Type: enum2$] // 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: enum2$ > >] // 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: enum2$ > >] // cdb-command: dx h -// cdb-check:h : Some [Type: enum$ >] -// cdb-check: [] [Type: enum$ >] -// cdb-check: [variant] : Some +// 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: [] [Type: enum$ >] -// cdb-check: [variant] : None +// 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$, 1, [...], Some>] -// cdb-check: [] [Type: enum$, 1, [...], Some>] -// cdb-check: [variant] : Some +// 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$ >, Ok>] -// cdb-check: [] [Type: enum$ >, Ok>] -// cdb-check: [variant] : Ok +// 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: 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: enum2$ >] + +// cdb-command: dx wrapping_niche128_dataful +// cdb-check: wrapping_niche128_dataful : X [Type: enum2$] +// 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: [+0x[...]] __0 [Type: msvc_pretty_enums::Wrapping128] + +// cdb-command: dx wrapping_niche128_none2 +// cdb-check: wrapping_niche128_none2 : Z [Type: enum2$] +// 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$] +// 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: 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: 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: 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: 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: 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: 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: 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: 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: enum2$] + +// cdb-command: dx -r3 niche_w_fields_std_result_ok,d +// 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: 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}; + pub enum CStyleEnum { Low = 2, High = 16, @@ -80,6 +152,51 @@ 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, u64), + B(u64), +} + +enum NicheLayoutWithFields3 { + A(u8, bool), + B(u8), + C(bool), + D(u8), + E(u8), + 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, +} + +#[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; @@ -93,6 +210,35 @@ 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 wrapping_niche128_dataful = + unsafe { Wrapping128Niche::X(Wrapping128(340282366920938463463374607431768211454)) }; + 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); + + 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); + + let arbitrary_discr1 = ArbitraryDiscr::Abc(1234); + let arbitrary_discr2 = ArbitraryDiscr::Def(5678); zzz(); // #break } diff --git a/src/test/debuginfo/msvc-scalarpair-params.rs b/src/test/debuginfo/msvc-scalarpair-params.rs index 3846fb42f81a..9630952cbaae 100644 --- a/src/test/debuginfo/msvc-scalarpair-params.rs +++ b/src/test/debuginfo/msvc-scalarpair-params.rs @@ -18,12 +18,10 @@ // cdb-command: g // cdb-command: dx o1 -// cdb-check:o1 : Some [Type: enum$ >] -// cdb-check: [variant] : Some +// cdb-check:o1 : Some [Type: enum2$ >] // cdb-check: [+0x004] __0 : 0x4d2 [Type: [...]] // cdb-command: dx o2 -// cdb-check:o2 : Some [Type: enum$ >] -// cdb-check: [variant] : Some +// cdb-check:o2 : Some [Type: enum2$ >] // 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/mutex.rs b/src/test/debuginfo/mutex.rs index 00dccf5f9064..314ba40b0e3d 100644 --- a/src/test/debuginfo/mutex.rs +++ b/src/test/debuginfo/mutex.rs @@ -20,19 +20,20 @@ // cdb-check: [] [Type: core::cell::UnsafeCell] // -// cdb-command:dx lock,d -// cdb-check:lock,d : Ok [Type: enum$,enum$ >, 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() -{ +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() {} diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 55a4ecc1c1a2..a51b37205e8a 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 @@ -118,20 +116,17 @@ // cdb-check: [chars] : "IAMA OS string [...]" // cdb-command: dx some -// cdb-check:some : Some [Type: enum$ >] -// cdb-check: [] [Type: enum$ >] -// cdb-check: [variant] : Some +// 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: [variant] : None +// cdb-check:none : None [Type: enum2$ >] +// cdb-check: [] [Type: enum2$ >] // 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: enum2$ >] +// cdb-check: [] [Type: enum2$ >] // 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/result-types.rs b/src/test/debuginfo/result-types.rs index c0d905a6acc4..cdac47a784d9 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 b040a6e74947..9cc99d7767c1 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$ >, 1, [...], Some>),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$ >, 1, [...], Some> +// 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 diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index ac6d80bb439b..0e2cc52a645b 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 {