debuginfo: Change C++-like encoding for enums.

The updated encoding should be able to handle niche layouts where
more than one variant has fields.
This commit is contained in:
Michael Woerister 2022-06-20 17:50:27 +02:00
parent e2b52ff73e
commit 622da5d834
15 changed files with 864 additions and 386 deletions

View File

@ -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)
}

View File

@ -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} {
/// <variant 0 fields>
/// struct Variant0 {
/// struct {name-of-variant-0} {
/// <variant 0 fields>
/// } value;
///
/// static VariantNames NAME = {name-of-variant-0};
/// static int_type DISCR_EXACT = {discriminant-of-variant-0};
/// } variant0;
///
/// <other variant structs>
/// {name} discriminant;
///
/// int_type tag;
///
/// enum VariantNames {
/// <name-of-variant-0> = 0, // The numeric values are variant index,
/// <name-of-variant-1> = 1, // not discriminant values.
/// <name-of-variant-2> = 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
/// 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.
///
/// ```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:
///
/// ```c
/// union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> {
/// struct <dataful variant name> {
/// <fields in dataful variant>
/// } dataful_variant;
/// enum Discriminant$ {
/// <non-dataful variants>
/// } 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,139 +238,346 @@ 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,
variant_struct_type_di_node,
)]
}
fn build_union_fields_for_direct_tag_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<Item = VariantIdx>,
tag_field: usize,
) -> SmallVec<&'ll DIType> {
let variant_field_infos: SmallVec<VariantFieldInfo<'ll>> = variant_indices
.map(|variant_index| {
let variant_layout = enum_type_and_layout.for_variant(cx, variant_index);
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,
),
source_info: None,
}
})
.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,
std::iter::once((
variant_index,
Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
)),
);
build_union_fields_for_direct_tag_enum_or_generator(
let variant_struct_type_wrapper_di_node = build_variant_struct_wrapper_type_di_node(
cx,
enum_type_and_layout,
enum_type_di_node,
&variant_field_infos,
discr_type_di_node,
tag_field,
)
}
fn build_union_fields_for_niche_tag_enum<'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<Item = VariantIdx>,
tag_field: usize,
) -> SmallVec<&'ll DIType> {
let dataful_variant_struct_type_di_node = super::build_enum_variant_struct_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),
);
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(
cx,
"Discriminant$",
variant_index,
None,
variant_struct_type_di_node,
variant_names_type_di_node,
tag_base_type_di_node,
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,
DiscrResult::NoDiscriminant,
);
smallvec![
build_field_di_node(
cx,
enum_type_di_node,
"dataful_variant",
&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,
dataful_variant_struct_type_di_node,
),
build_field_di_node(
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,
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_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: impl Iterator<Item = VariantIdx> + Clone,
tag_field: usize,
dataful_variant_index: Option<VariantIdx>,
) -> 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<VariantFieldInfo<'ll>> = 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,
source_info: None,
discr: super::compute_discriminant_value(cx, enum_type_and_layout, variant_index),
}
})
.collect();
build_union_fields_for_direct_tag_enum_or_generator(
cx,
enum_type_and_layout,
enum_type_di_node,
&variant_field_infos,
variant_names_type_di_node,
tag_base_type,
tag_field,
dataful_variant_index,
)
}
// 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>,
containing_scope: &'ll DIType,
variants: impl Iterator<Item = (VariantIdx, Cow<'tcx, str>)>,
) -> &'ll DIType {
// Create an enumerator for each variant.
super::build_enumeration_type_di_node(
cx,
"VariantNames",
variant_names_enum_base_type(cx),
variants.map(|(variant_index, variant_name)| (variant_name, variant_index.as_u32() as u64)),
containing_scope,
)
}
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<VariantIdx>,
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,
type_map::stub(
cx,
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>(
cx: &CodegenCx<'ll, 'tcx>,
generator_type_and_layout: TyAndLayout<'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<VariantIdx, DiscrResult> = 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<VariantFieldInfo<'ll>> = 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<VariantIdx>,
) -> 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<VariantIdx>,
) -> 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())
}

View File

@ -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<Item = (Discr<'tcx>, Cow<'tcx, str>)>,
enumerators: impl Iterator<Item = (Cow<'tcx, str>, 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<Option<&'ll DIType>> = 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<Option<&'ll DIType>> = 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::<SmallVec<_>>()
},
|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<u128> {
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<u64> {
) -> 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)
}
}
}

View File

@ -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,
)

View File

@ -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<PolyExistentialTraitRef<'tcx>>, 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>,

View File

@ -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,

View File

@ -18,11 +18,10 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability};
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, ExistentialProjection, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
use rustc_target::abi::{Integer, TagEncoding, Variants};
use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt};
use rustc_target::abi::Integer;
use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt::Write;
use crate::debuginfo::wants_c_like_enum_debuginfo;
@ -98,7 +97,6 @@ fn push_debuginfo_type_name<'tcx>(
if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
msvc_enum_fallback(
tcx,
ty_and_layout,
&|output, visited| {
push_item_name(tcx, def.did(), true, output);
@ -395,7 +393,6 @@ fn push_debuginfo_type_name<'tcx>(
if cpp_like_debuginfo && t.is_generator() {
let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
msvc_enum_fallback(
tcx,
ty_and_layout,
&|output, visited| {
push_closure_or_generator_name(tcx, def_id, substs, true, output, visited);
@ -428,58 +425,17 @@ fn push_debuginfo_type_name<'tcx>(
/// MSVC names enums differently than other platforms so that the debugging visualization
// format (natvis) is able to understand enums and render the active variant correctly in the
// debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
// `EnumMemberDescriptionFactor::create_member_descriptions`.
// debugger. For more information, look in
// rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs.
fn msvc_enum_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
ty_and_layout: TyAndLayout<'tcx>,
push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
output: &mut String,
visited: &mut FxHashSet<Ty<'tcx>>,
) {
debug_assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
let ty = ty_and_layout.ty;
output.push_str("enum$<");
push_inner(output, visited);
let variant_name = |variant_index| match ty.kind() {
ty::Adt(adt_def, _) => {
debug_assert!(adt_def.is_enum());
Cow::from(adt_def.variant(variant_index).name.as_str())
}
ty::Generator(..) => GeneratorSubsts::variant_name(variant_index),
_ => unreachable!(),
};
if let Variants::Multiple {
tag_encoding: TagEncoding::Niche { dataful_variant, .. },
tag,
variants,
..
} = &ty_and_layout.variants
{
let dataful_variant_layout = &variants[*dataful_variant];
// calculate the range of values for the dataful variant
let dataful_discriminant_range =
dataful_variant_layout.largest_niche().unwrap().valid_range;
let min = dataful_discriminant_range.start;
let min = tag.size(&tcx).truncate(min);
let max = dataful_discriminant_range.end;
let max = tag.size(&tcx).truncate(max);
let dataful_variant_name = variant_name(*dataful_variant);
write!(output, ", {}, {}, {}", min, max, dataful_variant_name).unwrap();
} else if let Variants::Single { index: variant_idx } = &ty_and_layout.variants {
// Uninhabited enums can't be constructed and should never need to be visualized so
// skip this step for them.
if !ty_and_layout.abi.is_uninhabited() {
write!(output, ", {}", variant_name(*variant_idx)).unwrap();
}
}
push_close_angle_bracket(true, output);
}

View File

@ -172,7 +172,9 @@ impl<I: Idx, T> IndexVec<I, T> {
}
#[inline]
pub fn indices(&self) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + 'static {
pub fn indices(
&self,
) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + Clone + 'static {
(0..self.len()).map(|n| I::new(n))
}

View File

@ -924,6 +924,30 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
fromRust(Flags), unwrapDI<DIType>(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<DIDescriptor>(Scope),
StringRef(Name, NameLen),
unwrapDI<DIFile>(File),
LineNo,
unwrapDI<DIType>(Ty),
fromRust(Flags),
unwrap<llvm::ConstantInt>(val),
AlignInBits
));
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock(
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
LLVMMetadataRef File, unsigned Line, unsigned Col) {

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="str">
<DisplayString>{(char*)data_ptr,[length]s8}</DisplayString>
@ -150,76 +150,122 @@
</Expand>
</Type>
<!-- Directly tagged enums. $T1 is the type name -->
<!--
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.
-->
<Type Name="enum$&lt;*&gt;">
<Intrinsic Name="tag" Expression="discriminant" />
<DisplayString Condition="tag() == 0">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 1" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 2" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 3" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 4" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 5" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 6" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 7" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 8" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 9" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 10" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 11" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 12" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 13" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 14" Optional="true">{tag(),en}</DisplayString>
<DisplayString Condition="tag() == 15" Optional="true">{tag(),en}</DisplayString>
<Intrinsic Name="in_range" Expression="(start &lt;= end) ? ((tag &gt;= start) &amp;&amp; (tag &lt;= end)) : ((tag &gt;= start) || (tag &lt;= end))">
<Parameter Name="start" Type="unsigned __int64" />
<Parameter Name="end" Type="unsigned __int64" />
</Intrinsic>
<Expand>
<Synthetic Name="[variant]">
<DisplayString>{tag(),en}</DisplayString>
</Synthetic>
<ExpandedItem Condition="tag() == 0">variant0</ExpandedItem>
<ExpandedItem Condition="tag() == 1" Optional="true">variant1</ExpandedItem>
<ExpandedItem Condition="tag() == 2" Optional="true">variant2</ExpandedItem>
<ExpandedItem Condition="tag() == 3" Optional="true">variant3</ExpandedItem>
<ExpandedItem Condition="tag() == 4" Optional="true">variant4</ExpandedItem>
<ExpandedItem Condition="tag() == 5" Optional="true">variant5</ExpandedItem>
<ExpandedItem Condition="tag() == 6" Optional="true">variant6</ExpandedItem>
<ExpandedItem Condition="tag() == 7" Optional="true">variant7</ExpandedItem>
<ExpandedItem Condition="tag() == 8" Optional="true">variant8</ExpandedItem>
<ExpandedItem Condition="tag() == 9" Optional="true">variant9</ExpandedItem>
<ExpandedItem Condition="tag() == 10" Optional="true">variant10</ExpandedItem>
<ExpandedItem Condition="tag() == 11" Optional="true">variant11</ExpandedItem>
<ExpandedItem Condition="tag() == 12" Optional="true">variant12</ExpandedItem>
<ExpandedItem Condition="tag() == 13" Optional="true">variant13</ExpandedItem>
<ExpandedItem Condition="tag() == 14" Optional="true">variant14</ExpandedItem>
<ExpandedItem Condition="tag() == 15" Optional="true">variant15</ExpandedItem>
</Expand>
</Type>
<Intrinsic Name="exact_match128" Expression="(tag128_hi == discr_hi) &amp;&amp; (tag128_lo == discr_lo)">
<Parameter Name="discr_hi" Type="unsigned __int64" />
<Parameter Name="discr_lo" Type="unsigned __int64" />
</Intrinsic>
<!-- Single variant enums. $T1 is the name of the enum, $T2 is the name of the variant -->
<Type Name="enum$&lt;*, *&gt;">
<DisplayString>{"$T2",sb}</DisplayString>
<Expand>
<Synthetic Name="[variant]">
<DisplayString>{"$T2",sb}</DisplayString>
</Synthetic>
<ExpandedItem>$T2</ExpandedItem>
</Expand>
</Type>
<Intrinsic Name="lt128" Expression="(x_hi &lt; y_hi) || ((x_hi == y_hi) &amp;&amp; (x_lo &lt; y_lo))">
<Parameter Name="x_hi" Type="unsigned __int64" />
<Parameter Name="x_lo" Type="unsigned __int64" />
<Parameter Name="y_hi" Type="unsigned __int64" />
<Parameter Name="y_lo" Type="unsigned __int64" />
</Intrinsic>
<!-- Niche-layout enums. $T1 is the name of the enum, $T2 is the low value of the dataful
variant tag, $T3 is the high value of the dataful variant tag, $T4 is the name of
the dataful variant -->
<Type Name="enum$&lt;*, *, *, *&gt;">
<Intrinsic Name="tag" Expression="discriminant" />
<Intrinsic Name="is_dataful" Expression="tag() &gt;= $T2 &amp;&amp; tag() &lt;= $T3" />
<DisplayString Condition="is_dataful()">{"$T4",sb}({dataful_variant})</DisplayString>
<DisplayString Condition="!is_dataful()">{discriminant,en}</DisplayString>
<Expand>
<ExpandedItem Condition="is_dataful()">dataful_variant</ExpandedItem>
<Synthetic Condition="is_dataful()" Name="[variant]">
<DisplayString>{"$T4",sb}</DisplayString>
</Synthetic>
<Synthetic Condition="!is_dataful()" Name="[variant]">
<DisplayString>{discriminant,en}</DisplayString>
</Synthetic>
<Intrinsic Name="lt_or_eq128" Expression="((x_hi == y_hi) &amp;&amp; (x_lo == y_lo)) || lt128(x_hi, x_lo, y_hi, y_lo)">
<Parameter Name="x_hi" Type="unsigned __int64" />
<Parameter Name="x_lo" Type="unsigned __int64" />
<Parameter Name="y_hi" Type="unsigned __int64" />
<Parameter Name="y_lo" Type="unsigned __int64" />
</Intrinsic>
<Intrinsic Name="in_range128" Expression="lt_or_eq128(begin_hi, begin_lo, tag128_hi, tag128_lo) &amp;&amp; lt_or_eq128(tag128_hi, tag128_lo, end_hi, end_lo)">
<Parameter Name="begin_hi" Type="unsigned __int64" />
<Parameter Name="begin_lo" Type="unsigned __int64" />
<Parameter Name="end_hi" Type="unsigned __int64" />
<Parameter Name="end_lo" Type="unsigned __int64" />
</Intrinsic>
<DisplayString Condition="tag == variant0.DISCR_EXACT" Optional="true">{variant0.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant1.DISCR_EXACT" Optional="true">{variant1.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant2.DISCR_EXACT" Optional="true">{variant2.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant3.DISCR_EXACT" Optional="true">{variant3.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant4.DISCR_EXACT" Optional="true">{variant4.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant5.DISCR_EXACT" Optional="true">{variant5.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant6.DISCR_EXACT" Optional="true">{variant6.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant7.DISCR_EXACT" Optional="true">{variant7.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant8.DISCR_EXACT" Optional="true">{variant8.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant9.DISCR_EXACT" Optional="true">{variant9.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant10.DISCR_EXACT" Optional="true">{variant10.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant11.DISCR_EXACT" Optional="true">{variant11.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant12.DISCR_EXACT" Optional="true">{variant12.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant13.DISCR_EXACT" Optional="true">{variant13.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant14.DISCR_EXACT" Optional="true">{variant14.NAME,en}</DisplayString>
<DisplayString Condition="tag == variant15.DISCR_EXACT" Optional="true">{variant15.NAME,en}</DisplayString>
<DisplayString Condition="in_range(variant_fallback.DISCR_BEGIN, variant_fallback.DISCR_END)" Optional="true">{variant_fallback.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant0.DISCR128_EXACT_HI, variant0.DISCR128_EXACT_LO)" Optional="true">{variant0.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant1.DISCR128_EXACT_HI, variant1.DISCR128_EXACT_LO)" Optional="true">{variant1.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant2.DISCR128_EXACT_HI, variant2.DISCR128_EXACT_LO)" Optional="true">{variant2.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant3.DISCR128_EXACT_HI, variant3.DISCR128_EXACT_LO)" Optional="true">{variant3.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant4.DISCR128_EXACT_HI, variant4.DISCR128_EXACT_LO)" Optional="true">{variant4.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant5.DISCR128_EXACT_HI, variant5.DISCR128_EXACT_LO)" Optional="true">{variant5.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant6.DISCR128_EXACT_HI, variant6.DISCR128_EXACT_LO)" Optional="true">{variant6.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant7.DISCR128_EXACT_HI, variant7.DISCR128_EXACT_LO)" Optional="true">{variant7.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant8.DISCR128_EXACT_HI, variant8.DISCR128_EXACT_LO)" Optional="true">{variant8.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant9.DISCR128_EXACT_HI, variant9.DISCR128_EXACT_LO)" Optional="true">{variant9.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant10.DISCR128_EXACT_HI, variant10.DISCR128_EXACT_LO)" Optional="true">{variant10.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant11.DISCR128_EXACT_HI, variant11.DISCR128_EXACT_LO)" Optional="true">{variant11.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant12.DISCR128_EXACT_HI, variant12.DISCR128_EXACT_LO)" Optional="true">{variant12.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant13.DISCR128_EXACT_HI, variant13.DISCR128_EXACT_LO)" Optional="true">{variant13.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant14.DISCR128_EXACT_HI, variant14.DISCR128_EXACT_LO)" Optional="true">{variant14.NAME,en}</DisplayString>
<DisplayString Condition="exact_match128(variant15.DISCR128_EXACT_HI, variant15.DISCR128_EXACT_LO)" Optional="true">{variant15.NAME,en}</DisplayString>
<DisplayString
Condition="in_range128(variant_fallback.DISCR128_BEGIN_HI, variant_fallback.DISCR128_BEGIN_LO, variant_fallback.DISCR128_END_HI, variant_fallback.DISCR128_END_LO)"
Optional="true">{variant_fallback.NAME,en}</DisplayString>
<Expand HideRawView="true">
<ExpandedItem Condition="tag == variant0.DISCR_EXACT" Optional="true">variant0.value</ExpandedItem>
<ExpandedItem Condition="tag == variant1.DISCR_EXACT" Optional="true">variant1.value</ExpandedItem>
<ExpandedItem Condition="tag == variant2.DISCR_EXACT" Optional="true">variant2.value</ExpandedItem>
<ExpandedItem Condition="tag == variant3.DISCR_EXACT" Optional="true">variant3.value</ExpandedItem>
<ExpandedItem Condition="tag == variant4.DISCR_EXACT" Optional="true">variant4.value</ExpandedItem>
<ExpandedItem Condition="tag == variant5.DISCR_EXACT" Optional="true">variant5.value</ExpandedItem>
<ExpandedItem Condition="tag == variant6.DISCR_EXACT" Optional="true">variant6.value</ExpandedItem>
<ExpandedItem Condition="tag == variant7.DISCR_EXACT" Optional="true">variant7.value</ExpandedItem>
<ExpandedItem Condition="tag == variant8.DISCR_EXACT" Optional="true">variant8.value</ExpandedItem>
<ExpandedItem Condition="tag == variant9.DISCR_EXACT" Optional="true">variant9.value</ExpandedItem>
<ExpandedItem Condition="tag == variant10.DISCR_EXACT" Optional="true">variant10.value</ExpandedItem>
<ExpandedItem Condition="tag == variant11.DISCR_EXACT" Optional="true">variant11.value</ExpandedItem>
<ExpandedItem Condition="tag == variant12.DISCR_EXACT" Optional="true">variant12.value</ExpandedItem>
<ExpandedItem Condition="tag == variant13.DISCR_EXACT" Optional="true">variant13.value</ExpandedItem>
<ExpandedItem Condition="tag == variant14.DISCR_EXACT" Optional="true">variant14.value</ExpandedItem>
<ExpandedItem Condition="tag == variant15.DISCR_EXACT" Optional="true">variant15.value</ExpandedItem>
<ExpandedItem Condition="in_range(variant_fallback.DISCR_BEGIN, variant_fallback.DISCR_END)" Optional="true">variant_fallback.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant0.DISCR128_EXACT_HI, variant0.DISCR128_EXACT_LO)" Optional="true">variant0.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant1.DISCR128_EXACT_HI, variant1.DISCR128_EXACT_LO)" Optional="true">variant1.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant2.DISCR128_EXACT_HI, variant2.DISCR128_EXACT_LO)" Optional="true">variant2.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant3.DISCR128_EXACT_HI, variant3.DISCR128_EXACT_LO)" Optional="true">variant3.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant4.DISCR128_EXACT_HI, variant4.DISCR128_EXACT_LO)" Optional="true">variant4.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant5.DISCR128_EXACT_HI, variant5.DISCR128_EXACT_LO)" Optional="true">variant5.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant6.DISCR128_EXACT_HI, variant6.DISCR128_EXACT_LO)" Optional="true">variant6.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant7.DISCR128_EXACT_HI, variant7.DISCR128_EXACT_LO)" Optional="true">variant7.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant8.DISCR128_EXACT_HI, variant8.DISCR128_EXACT_LO)" Optional="true">variant8.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant9.DISCR128_EXACT_HI, variant9.DISCR128_EXACT_LO)" Optional="true">variant9.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant10.DISCR128_EXACT_HI, variant10.DISCR128_EXACT_LO)" Optional="true">variant10.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant11.DISCR128_EXACT_HI, variant11.DISCR128_EXACT_LO)" Optional="true">variant11.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant12.DISCR128_EXACT_HI, variant12.DISCR128_EXACT_LO)" Optional="true">variant12.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant13.DISCR128_EXACT_HI, variant13.DISCR128_EXACT_LO)" Optional="true">variant13.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant14.DISCR128_EXACT_HI, variant14.DISCR128_EXACT_LO)" Optional="true">variant14.value</ExpandedItem>
<ExpandedItem Condition="exact_match128(variant15.DISCR128_EXACT_HI, variant15.DISCR128_EXACT_LO)" Optional="true">variant15.value</ExpandedItem>
<ExpandedItem
Condition="in_range128(variant_fallback.DISCR128_BEGIN_HI, variant_fallback.DISCR128_BEGIN_LO, variant_fallback.DISCR128_END_HI, variant_fallback.DISCR128_END_LO)"
Optional="true">variant_fallback.value</ExpandedItem>
</Expand>
</Type>
</AutoVisualizer>

View File

@ -42,13 +42,11 @@
// cdb-command: g
// cdb-command: dx b
// cdb-check: b : Unresumed [Type: enum$<generator_objects::main::generator_env$0>]
// cdb-check: [variant] : Unresumed
// cdb-check: [+0x[...]] _ref__a : 0x[...] : 5 [Type: int *]
// cdb-command: g
// cdb-command: dx b
// cdb-check: b : Suspend0 [Type: enum$<generator_objects::main::generator_env$0>]
// cdb-check: [variant] : Suspend0
// cdb-check: [+0x[...]] c : 6 [Type: int]
// cdb-check: [+0x[...]] d : 7 [Type: int]
// cdb-check: [+0x[...]] _ref__a : 0x[...] : 5 [Type: int *]
@ -56,7 +54,6 @@
// cdb-command: g
// cdb-command: dx b
// cdb-check: b : Suspend1 [Type: enum$<generator_objects::main::generator_env$0>]
// cdb-check: [variant] : Suspend1
// cdb-check: [+0x[...]] c : 7 [Type: int]
// cdb-check: [+0x[...]] d : 8 [Type: int]
// cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *]
@ -64,8 +61,6 @@
// cdb-command: g
// cdb-command: dx b
// cdb-check: b : Returned [Type: enum$<generator_objects::main::generator_env$0>]
// cdb-check: [<Raw View>] [Type: enum$<generator_objects::main::generator_env$0>]
// cdb-check: [variant] : Returned
// cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *]
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]

View File

@ -4,69 +4,110 @@
// cdb-command: g
// cdb-command: dx a
// cdb-check:a : Some({...}) [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum>, 2, 16, Some>]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum>, 2, 16, Some>]
// cdb-check: [variant] : Some
// cdb-check:a : Some [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum> >]
// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
// cdb-command: dx b
// cdb-check:b : None [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum>, 2, 16, Some>]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum>, 2, 16, Some>]
// cdb-check: [variant] : None
// cdb-check:b : None [Type: enum$<core::option::Option<msvc_pretty_enums::CStyleEnum> >]
// cdb-command: dx c
// cdb-check:c : Tag1 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
// cdb-check: [<Raw View>] [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
// cdb-check: [variant] : Tag1
// cdb-check:c : Tag1 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum>]
// cdb-command: dx d
// cdb-check:d : Data({...}) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
// cdb-check: [<Raw View>] [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
// cdb-check: [variant] : Data
// cdb-check:d : Data [Type: enum$<msvc_pretty_enums::NicheLayoutEnum>]
// cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
// cdb-command: dx e
// cdb-check:e : Tag2 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
// cdb-check: [<Raw View>] [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
// cdb-check: [variant] : Tag2
// cdb-check:e : Tag2 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum>]
// cdb-command: dx f
// cdb-check:f : Some({...}) [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
// cdb-check: [variant] : Some
// cdb-check:f : Some [Type: enum$<core::option::Option<ref$<u32> > >]
// cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *]
// cdb-command: dx g
// cdb-check:g : None [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<ref$<u32> >, 1, [...], Some>]
// cdb-check: [variant] : None
// cdb-check:g : None [Type: enum$<core::option::Option<ref$<u32> > >]
// cdb-command: dx h
// cdb-check:h : Some [Type: enum$<core::option::Option<u32> >]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<u32> >]
// cdb-check: [variant] : Some
// cdb-check: [+0x004] __0 : 0xc [Type: unsigned int]
// cdb-command: dx i
// cdb-check:i : None [Type: enum$<core::option::Option<u32> >]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<u32> >]
// cdb-check: [variant] : None
// cdb-command: dx j
// cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
// cdb-command: dx k
// cdb-check:k : Some({...}) [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
// cdb-check: [variant] : Some
// cdb-check:k : Some [Type: enum$<core::option::Option<alloc::string::String> >]
// cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String]
// cdb-command: dx l
// cdb-check:l : Ok [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>]
// cdb-check: [<Raw View>] [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> >, Ok>]
// cdb-check: [variant] : Ok
// cdb-check:l : Ok [Type: enum$<core::result::Result<u32,enum$<msvc_pretty_enums::Empty> > >]
// cdb-check: [+0x000] __0 : 0x2a [Type: unsigned int]
// cdb-command: dx niche128_some
// cdb-check:niche128_some : Some [Type: enum$<core::option::Option<core::num::nonzero::NonZeroI128> >]
// 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$<core::option::Option<core::num::nonzero::NonZeroI128> >]
// cdb-command: dx niche_w_fields_1_some,d
// cdb-check: niche_w_fields_1_some,d : A [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields1>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields1>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields2>]
// cdb-check: [<Raw View>] [Type: enum$<msvc_pretty_enums::NicheLayoutWithFields2>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields2>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields3>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields3>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields3>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields3>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields3>]
// 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$<msvc_pretty_enums::NicheLayoutWithFields3>]
// cdb-command: dx -r3 niche_w_fields_std_result_ok,d
// cdb-check: niche_w_fields_std_result_ok,d : Ok [Type: enum$<core::result::Result<alloc::boxed::Box<slice$<u8>,alloc::alloc::Global>,u64> >]
// cdb-check: [+0x[...]] __0 [Type: alloc::boxed::Box<slice$<u8>,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$<core::result::Result<alloc::boxed::Box<slice$<u8>,alloc::alloc::Global>,u64> >]
// cdb-check: [+0x[...]] __0 : 789 [Type: unsigned __int64]
use std::num::{NonZeroI128, NonZeroU32};
pub enum CStyleEnum {
Low = 2,
High = 16,
@ -80,6 +121,27 @@ pub enum NicheLayoutEnum {
pub enum Empty {}
// The following three types will use a niche layout once
// https://github.com/rust-lang/rust/pull/94075 is merged:
enum NicheLayoutWithFields1<'a> {
A(&'a u8, u32),
B(u32),
}
enum NicheLayoutWithFields2 {
A(NonZeroU32, usize),
B(usize),
}
enum NicheLayoutWithFields3 {
A(u8, bool),
B(u8),
C(bool),
D(u8),
E(u8),
F,
}
fn main() {
let a = Some(CStyleEnum::Low);
let b = Option::<CStyleEnum>::None;
@ -93,6 +155,24 @@ fn main() {
let j = CStyleEnum::High;
let k = Some("IAMA optional string!".to_string());
let l = Result::<u32, Empty>::Ok(42);
let niche128_some = Some(NonZeroI128::new(123456).unwrap());
let niche128_none: Option<NonZeroI128> = None;
let niche_w_fields_1_some = NicheLayoutWithFields1::A(&77, 7);
let niche_w_fields_1_none = NicheLayoutWithFields1::B(99);
let niche_w_fields_2_some = NicheLayoutWithFields2::A(NonZeroU32::new(800).unwrap(), 900);
let niche_w_fields_2_none = NicheLayoutWithFields2::B(1000);
let niche_w_fields_3_some = NicheLayoutWithFields3::A(137, true);
let niche_w_fields_3_niche1 = NicheLayoutWithFields3::B(12);
let niche_w_fields_3_niche2 = NicheLayoutWithFields3::C(false);
let niche_w_fields_3_niche3 = NicheLayoutWithFields3::D(34);
let niche_w_fields_3_niche4 = NicheLayoutWithFields3::E(56);
let niche_w_fields_3_niche5 = NicheLayoutWithFields3::F;
let niche_w_fields_std_result_ok: Result<Box<[u8]>, u64> = Ok(vec![1, 2, 3].into());
let niche_w_fields_std_result_err: Result<Box<[u8]>, u64> = Err(789);
zzz(); // #break
}

View File

@ -19,11 +19,9 @@
// cdb-command: dx o1
// cdb-check:o1 : Some [Type: enum$<core::option::Option<u32> >]
// cdb-check: [variant] : Some
// cdb-check: [+0x004] __0 : 0x4d2 [Type: [...]]
// cdb-command: dx o2
// cdb-check:o2 : Some [Type: enum$<core::option::Option<u64> >]
// cdb-check: [variant] : Some
// cdb-check: [+0x008] __0 : 0x162e [Type: unsigned __int64]
// cdb-command: g
@ -89,7 +87,7 @@ fn slice(s: &[u8]) {
zzz(); // #break
}
fn zzz() { }
fn zzz() {}
fn main() {
range(10..12, 20..30);

View File

@ -39,7 +39,6 @@
// gdb-command: print some_string
// gdb-check:$8 = Some = {"IAMA "...}
// === LLDB TESTS ==================================================================================
// lldb-command: run
@ -65,7 +64,6 @@
// lldb-command: print os_string
// lldb-check:[...]$6 = "IAMA OS string 😃"[...]
// === CDB TESTS ==================================================================================
// cdb-command: g
@ -120,18 +118,15 @@
// cdb-command: dx some
// cdb-check:some : Some [Type: enum$<core::option::Option<i16> >]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<i16> >]
// cdb-check: [variant] : Some
// cdb-check: [+0x002] __0 : 8 [Type: short]
// cdb-command: dx none
// cdb-check:none : None [Type: enum$<core::option::Option<i64> >]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<i64> >]
// cdb-check: [variant] : None
// cdb-command: dx some_string
// cdb-check:some_string : Some({...}) [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
// cdb-check: [variant] : Some
// cdb-check:some_string : Some [Type: enum$<core::option::Option<alloc::string::String> >]
// cdb-check: [<Raw View>] [Type: enum$<core::option::Option<alloc::string::String> >]
// 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() {
()
}

View File

@ -240,14 +240,14 @@
// cdb-check:struct tuple$<usize (*)(f64),usize> rust_fn_with_return_value = [...]
// cdb-check:struct tuple$<void (*)(enum$<core::result::Result<char,f64> >),usize> unsafe_fn = [...]
// cdb-check:struct tuple$<void (*)(isize),usize> extern_c_fn = [...]
// cdb-check:struct tuple$<void (*)(enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> >, 1, [...], Some>),usize> rust_fn = [...]
// cdb-check:struct tuple$<void (*)(enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> > >),usize> rust_fn = [...]
// cdb-command:dv /t *_function*
// cdb-check:struct tuple$<isize (*)(ptr_const$<u8>, ...),usize> variadic_function = [...]
// cdb-check:struct tuple$<type_names::mod1::mod2::Struct3 (*)(type_names::mod1::mod2::Struct3),usize> generic_function_struct3 = [...]
// cdb-check:struct tuple$<isize (*)(isize),usize> 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$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> >, 1, [...], Some>
// cdb-check:Parameter Types: enum$<core::option::Option<isize> >,enum$<core::option::Option<ref$<type_names::mod1::Struct2> > >
// 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