mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-03 13:37:37 +00:00
97 lines
3.8 KiB
Rust
97 lines
3.8 KiB
Rust
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)
|
|
})
|
|
}
|
|
|
|
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))
|
|
}
|
|
}
|
|
}
|