1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
use rustc_middle::bug;
use rustc_middle::ty::layout::{IntegerExt, PrimitiveExt, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_target::abi::{Integer, Primitive, Size, TagEncoding, Variants};
// FIXME(eddyb) find a place for this (or a way to replace it).
pub mod type_names;
/// Returns true if we want to generate a DW_TAG_enumeration_type description for
/// this instead of a DW_TAG_struct_type with DW_TAG_variant_part.
///
/// NOTE: This is somewhat inconsistent right now: For empty enums and enums with a single
/// fieldless variant, we generate DW_TAG_struct_type, although a
/// DW_TAG_enumeration_type would be a better fit.
pub fn wants_c_like_enum_debuginfo<'tcx>(
tcx: TyCtxt<'tcx>,
enum_type_and_layout: TyAndLayout<'tcx>,
) -> bool {
match enum_type_and_layout.ty.kind() {
ty::Adt(adt_def, _) => {
if !adt_def.is_enum() {
return false;
}
if type_names::cpp_like_debuginfo(tcx)
&& tag_base_type_opt(tcx, enum_type_and_layout)
.map(|ty| ty.primitive_size(tcx).bits())
== Some(128)
{
// C++-like debuginfo never uses the C-like representation for 128-bit enums.
return false;
}
match adt_def.variants().len() {
0 => false,
1 => {
// Univariant enums unless they are zero-sized
enum_type_and_layout.size != Size::ZERO && adt_def.all_fields().count() == 0
}
_ => {
// Enums with more than one variant if they have no fields
adt_def.all_fields().count() == 0
}
}
}
_ => false,
}
}
/// Extract the type with which we want to describe the tag of the given enum or coroutine.
pub fn tag_base_type<'tcx>(tcx: TyCtxt<'tcx>, enum_type_and_layout: TyAndLayout<'tcx>) -> Ty<'tcx> {
tag_base_type_opt(tcx, enum_type_and_layout).unwrap_or_else(|| {
bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
})
}
pub fn tag_base_type_opt<'tcx>(
tcx: TyCtxt<'tcx>,
enum_type_and_layout: TyAndLayout<'tcx>,
) -> Option<Ty<'tcx>> {
assert!(match enum_type_and_layout.ty.kind() {
ty::Coroutine(..) => true,
ty::Adt(adt_def, _) => adt_def.is_enum(),
_ => false,
});
match enum_type_and_layout.layout.variants() {
// A single-variant enum has no discriminant.
Variants::Single { .. } => None,
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
// Niche tags are always normalized to unsized integers of the correct size.
Some(
match tag.primitive() {
Primitive::Int(t, _) => t,
Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => {
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be
// a RawPtr. CodeView doesn't know what to do with enums whose base type is a
// pointer so we fix this up to just be `usize`.
// DWARF might be able to deal with this but with an integer type we are on
// the safe side there too.
tcx.data_layout.ptr_sized_integer()
}
}
.to_ty(tcx, false),
)
}
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
// Direct tags preserve the sign.
Some(tag.primitive().to_ty(tcx))
}
}
}