use std::cell::RefCell; use rustc_data_structures::{ fingerprint::Fingerprint, fx::FxHashMap, stable_hasher::{HashStable, StableHasher}, }; use rustc_middle::{ bug, ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}, }; use rustc_target::abi::{Align, Size, VariantIdx}; use crate::{ common::CodegenCx, debuginfo::utils::{create_DIArray, debug_context, DIB}, llvm::{ self, debuginfo::{DIFlags, DIScope, DIType}, }, }; use super::{unknown_file_metadata, SmallVec, UNKNOWN_LINE_NUMBER}; mod private { // This type cannot be constructed outside of this module because // it has a private field. We make use of this in order to prevent // `UniqueTypeId` from being constructed directly, without asserting // the preconditions. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)] pub struct HiddenZst; } /// A unique identifier for anything that we create a debuginfo node for. /// The types it contains are expected to already be normalized (which /// is debug_asserted in the constructors). /// /// Note that there are some things that only show up in debuginfo, like /// the separate type descriptions for each enum variant. These get an ID /// too because they have their own debuginfo node in LLVM IR. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)] pub(super) enum UniqueTypeId<'tcx> { /// The ID of a regular type as it shows up at the language level. Ty(Ty<'tcx>, private::HiddenZst), /// The ID for the single DW_TAG_variant_part nested inside the top-level /// DW_TAG_structure_type that describes enums and coroutines. 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>, private::HiddenZst), } impl<'tcx> UniqueTypeId<'tcx> { pub fn for_ty(tcx: TyCtxt<'tcx>, t: Ty<'tcx>) -> Self { debug_assert_eq!(t, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)); UniqueTypeId::Ty(t, private::HiddenZst) } pub fn for_enum_variant_part(tcx: TyCtxt<'tcx>, enum_ty: Ty<'tcx>) -> Self { debug_assert_eq!(enum_ty, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), enum_ty)); UniqueTypeId::VariantPart(enum_ty, private::HiddenZst) } pub fn for_enum_variant_struct_type( 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::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>, implemented_trait: Option>, ) -> Self { debug_assert_eq!( self_type, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), self_type) ); debug_assert_eq!( implemented_trait, tcx.normalize_erasing_regions(ParamEnv::reveal_all(), implemented_trait) ); UniqueTypeId::VTableTy(self_type, implemented_trait, private::HiddenZst) } /// Generates a string version of this [UniqueTypeId], which can be used as the `UniqueId` /// argument of the various `LLVMRustDIBuilderCreate*Type()` methods. /// /// Right now this takes the form of a hex-encoded opaque hash value. pub fn generate_unique_id_string(self, tcx: TyCtxt<'tcx>) -> String { let mut hasher = StableHasher::new(); tcx.with_stable_hashing_context(|mut hcx| { hcx.while_hashing_spans(false, |hcx| self.hash_stable(hcx, &mut hasher)) }); hasher.finish::().to_hex() } pub fn expect_ty(self) -> Ty<'tcx> { match self { UniqueTypeId::Ty(ty, _) => ty, _ => bug!("Expected `UniqueTypeId::Ty` but found `{:?}`", self), } } } /// The `TypeMap` is where the debug context holds the type metadata nodes /// created so far. The debuginfo nodes are identified by `UniqueTypeId`. #[derive(Default)] pub(crate) struct TypeMap<'ll, 'tcx> { pub(super) unique_id_to_di_node: RefCell, &'ll DIType>>, } impl<'ll, 'tcx> TypeMap<'ll, 'tcx> { /// Adds a `UniqueTypeId` to metadata mapping to the `TypeMap`. The method will /// fail if the mapping already exists. pub(super) fn insert(&self, unique_type_id: UniqueTypeId<'tcx>, metadata: &'ll DIType) { if self.unique_id_to_di_node.borrow_mut().insert(unique_type_id, metadata).is_some() { bug!("type metadata for unique ID '{:?}' is already in the `TypeMap`!", unique_type_id); } } pub(super) fn di_node_for_unique_id( &self, unique_type_id: UniqueTypeId<'tcx>, ) -> Option<&'ll DIType> { self.unique_id_to_di_node.borrow().get(&unique_type_id).cloned() } } pub struct DINodeCreationResult<'ll> { pub di_node: &'ll DIType, pub already_stored_in_typemap: bool, } impl<'ll> DINodeCreationResult<'ll> { pub fn new(di_node: &'ll DIType, already_stored_in_typemap: bool) -> Self { DINodeCreationResult { di_node, already_stored_in_typemap } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Stub<'ll> { Struct, Union, VTableTy { vtable_holder: &'ll DIType }, } pub struct StubInfo<'ll, 'tcx> { metadata: &'ll DIType, unique_type_id: UniqueTypeId<'tcx>, } impl<'ll, 'tcx> StubInfo<'ll, 'tcx> { pub(super) fn new( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, build: impl FnOnce(&CodegenCx<'ll, 'tcx>, /* unique_type_id_str: */ &str) -> &'ll DIType, ) -> StubInfo<'ll, 'tcx> { let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx); let di_node = build(cx, &unique_type_id_str); StubInfo { metadata: di_node, unique_type_id } } } /// Create a stub debuginfo node onto which fields and nested types can be attached. pub(super) fn stub<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, kind: Stub<'ll>, unique_type_id: UniqueTypeId<'tcx>, name: &str, (size, align): (Size, Align), containing_scope: Option<&'ll DIScope>, flags: DIFlags, ) -> StubInfo<'ll, 'tcx> { let empty_array = create_DIArray(DIB(cx), &[]); let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx); let metadata = match kind { Stub::Struct | Stub::VTableTy { .. } => { let vtable_holder = match kind { Stub::VTableTy { vtable_holder } => Some(vtable_holder), _ => None, }; unsafe { llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, name.as_ptr().cast(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, flags, None, empty_array, 0, vtable_holder, unique_type_id_str.as_ptr().cast(), unique_type_id_str.len(), ) } } Stub::Union => unsafe { llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), containing_scope, name.as_ptr().cast(), name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, flags, Some(empty_array), 0, unique_type_id_str.as_ptr().cast(), unique_type_id_str.len(), ) }, }; StubInfo { metadata, unique_type_id } } /// This function enables creating debuginfo nodes that can recursively refer to themselves. /// It will first insert the given stub into the type map and only then execute the `members` /// and `generics` closures passed in. These closures have access to the stub so they can /// directly attach fields to them. If the type of a field transitively refers back /// to the type currently being built, the stub will already be found in the type map, /// which effectively breaks the recursion cycle. pub(super) fn build_type_with_children<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, stub_info: StubInfo<'ll, 'tcx>, members: impl FnOnce(&CodegenCx<'ll, 'tcx>, &'ll DIType) -> SmallVec<&'ll DIType>, generics: impl FnOnce(&CodegenCx<'ll, 'tcx>) -> SmallVec<&'ll DIType>, ) -> DINodeCreationResult<'ll> { debug_assert_eq!( debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None ); debug_context(cx).type_map.insert(stub_info.unique_type_id, stub_info.metadata); let members: SmallVec<_> = members(cx, stub_info.metadata).into_iter().map(|node| Some(node)).collect(); let generics: SmallVec> = generics(cx).into_iter().map(|node| Some(node)).collect(); if !(members.is_empty() && generics.is_empty()) { unsafe { let members_array = create_DIArray(DIB(cx), &members[..]); let generics_array = create_DIArray(DIB(cx), &generics[..]); llvm::LLVMRustDICompositeTypeReplaceArrays( DIB(cx), stub_info.metadata, Some(members_array), Some(generics_array), ); } } DINodeCreationResult { di_node: stub_info.metadata, already_stored_in_typemap: true } }