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