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:
parent
e2b52ff73e
commit
622da5d834
15 changed files with 864 additions and 386 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue