diff --git a/Cargo.lock b/Cargo.lock index 7a1dd32e0ac15..cb397821d1c89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3524,6 +3524,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_llvm", + "rustc_macros", "rustc_metadata", "rustc_middle", "rustc_query_system", diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 3b410c2cb4a7e..67183ff5887e9 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -25,6 +25,7 @@ rustc_fs_util = { path = "../rustc_fs_util" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_llvm = { path = "../rustc_llvm" } +rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index d515502d445a9..89fc898003737 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -23,9 +23,7 @@ use cstr::cstr; use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo; use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind; use rustc_codegen_ssa::traits::*; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_fs_util::path_to_c_string; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -37,7 +35,6 @@ use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{ self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES, }; -use rustc_query_system::ich::NodeIdHashingMode; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::Symbol; use rustc_span::FileNameDisplayPreference; @@ -45,9 +42,11 @@ use rustc_span::{self, SourceFile, SourceFileHash}; use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, TagEncoding}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{Primitive, Size, VariantIdx, Variants}; +use smallvec::SmallVec; use tracing::debug; use libc::{c_longlong, c_uint}; +use std::cell::RefCell; use std::collections::hash_map::Entry; use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; @@ -95,193 +94,127 @@ pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0; pub const NO_SCOPE_METADATA: Option<&DIScope> = None; mod unique_type_id { - use super::*; - use rustc_arena::DroplessArena; - - #[derive(Copy, Hash, Eq, PartialEq, Clone)] - pub(super) struct UniqueTypeId(u32); + use rustc_data_structures::{ + fingerprint::Fingerprint, + stable_hasher::{HashStable, NodeIdHashingMode, StableHasher}, + }; + use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; + use rustc_target::abi::VariantIdx; + + // 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 { + _inaccessible: (), + } - // The `&'static str`s in this type actually point into the arena. - // - // The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278 - // found that to regress performance up to 2% in some cases. This might be - // revisited after further improvements to `indexmap`. - #[derive(Default)] - pub(super) struct TypeIdInterner { - arena: DroplessArena, - names: FxHashMap<&'static str, UniqueTypeId>, - strings: Vec<&'static str>, + /// 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>, HiddenZst), + /// The ID for the artificial struct type describing a single enum variant. + Variant(Ty<'tcx>, VariantIdx, HiddenZst), + /// The ID for the single DW_TAG_variant_part nested inside the top-level + /// DW_TAG_structure_type that describes enums and generators. + VariantPart(Ty<'tcx>, HiddenZst), + /// The ID of the artificial type we create for VTables. + VTableTy(Ty<'tcx>, Option>, HiddenZst), } - impl TypeIdInterner { - #[inline] - pub(super) fn intern(&mut self, string: &str) -> UniqueTypeId { - if let Some(&name) = self.names.get(string) { - return name; - } + 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, HiddenZst { _inaccessible: () }) + } + + pub fn for_enum_variant( + 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::Variant(enum_ty, variant_idx, HiddenZst { _inaccessible: () }) + } - let name = UniqueTypeId(self.strings.len() as u32); - - // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be - // UTF-8. - let string: &str = - unsafe { std::str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) }; - // It is safe to extend the arena allocation to `'static` because we only access - // these while the arena is still alive. - let string: &'static str = unsafe { &*(string as *const str) }; - self.strings.push(string); - self.names.insert(string, name); - name + 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, HiddenZst { _inaccessible: () }) } - // Get the symbol as a string. `Symbol::as_str()` should be used in - // preference to this function. - pub(super) fn get(&self, symbol: UniqueTypeId) -> &str { - self.strings[symbol.0 as usize] + 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, HiddenZst { _inaccessible: () }) + } + + /// 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(); + let mut hcx = tcx.create_stable_hashing_context(); + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + self.hash_stable(hcx, &mut hasher); + }); + }); + hasher.finish::().to_hex() } } } use unique_type_id::*; -/// The `TypeMap` is where the `CrateDebugContext` holds the type metadata nodes -/// created so far. The metadata nodes are indexed by `UniqueTypeId`, and, for -/// faster lookup, also by `Ty`. The `TypeMap` is responsible for creating -/// `UniqueTypeId`s. +/// The `TypeMap` is where the debug context holds the type metadata nodes +/// created so far. The metadata nodes are indexed by `UniqueTypeId`. #[derive(Default)] pub struct TypeMap<'ll, 'tcx> { - /// The `UniqueTypeId`s created so far. - unique_id_interner: TypeIdInterner, - /// A map from `UniqueTypeId` to debuginfo metadata for that type. This is a 1:1 mapping. - unique_id_to_metadata: FxHashMap, - /// A map from types to debuginfo metadata. This is an N:1 mapping. - type_to_metadata: FxHashMap, &'ll DIType>, - /// A map from types to `UniqueTypeId`. This is an N:1 mapping. - type_to_unique_id: FxHashMap, UniqueTypeId>, + unique_id_to_metadata: RefCell, &'ll DIType>>, } impl<'ll, 'tcx> TypeMap<'ll, 'tcx> { - /// Adds a Ty to metadata mapping to the TypeMap. The method will fail if - /// the mapping already exists. - fn register_type_with_metadata(&mut self, type_: Ty<'tcx>, metadata: &'ll DIType) { - if self.type_to_metadata.insert(type_, metadata).is_some() { - bug!("type metadata for `Ty` '{}' is already in the `TypeMap`!", type_); - } - } - - /// Removes a `Ty`-to-metadata mapping. - /// This is useful when computing the metadata for a potentially - /// recursive type (e.g., a function pointer of the form: - /// - /// fn foo() -> impl Copy { foo } - /// - /// This kind of type cannot be properly represented - /// via LLVM debuginfo. As a workaround, - /// we register a temporary Ty to metadata mapping - /// for the function before we compute its actual metadata. - /// If the metadata computation ends up recursing back to the - /// original function, it will use the temporary mapping - /// for the inner self-reference, preventing us from - /// recursing forever. - /// - /// This function is used to remove the temporary metadata - /// mapping after we've computed the actual metadata. - fn remove_type(&mut self, ty: Ty<'tcx>) { - if self.type_to_metadata.remove(&ty).is_none() { - bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", ty); - } - } - /// Adds a `UniqueTypeId` to metadata mapping to the `TypeMap`. The method will /// fail if the mapping already exists. fn register_unique_id_with_metadata( - &mut self, - unique_type_id: UniqueTypeId, + &self, + unique_type_id: UniqueTypeId<'tcx>, metadata: &'ll DIType, ) { - if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() { - bug!( - "type metadata for unique ID '{}' is already in the `TypeMap`!", - self.get_unique_type_id_as_string(unique_type_id) - ); + if self.unique_id_to_metadata.borrow_mut().insert(unique_type_id, metadata).is_some() { + bug!("type metadata for unique ID '{:?}' is already in the `TypeMap`!", unique_type_id); } } - fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option<&'ll DIType> { - self.type_to_metadata.get(&type_).cloned() - } - - fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<&'ll DIType> { - self.unique_id_to_metadata.get(&unique_type_id).cloned() - } - - /// Gets the string representation of a `UniqueTypeId`. This method will fail if - /// the ID is unknown. - fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str { - self.unique_id_interner.get(unique_type_id) - } - - /// Gets the `UniqueTypeId` for the given type. If the `UniqueTypeId` for the given - /// type has been requested before, this is just a table lookup. Otherwise, an - /// ID will be generated and stored for later lookup. - fn get_unique_type_id_of_type<'a>( - &mut self, - cx: &CodegenCx<'a, 'tcx>, - type_: Ty<'tcx>, - ) -> UniqueTypeId { - // Let's see if we already have something in the cache. - if let Some(unique_type_id) = self.type_to_unique_id.get(&type_).cloned() { - return unique_type_id; - } - // If not, generate one. - - // The hasher we are using to generate the UniqueTypeId. We want - // something that provides more than the 64 bits of the DefaultHasher. - let mut hasher = StableHasher::new(); - let mut hcx = cx.tcx.create_stable_hashing_context(); - let type_ = cx.tcx.erase_regions(type_); - hcx.while_hashing_spans(false, |hcx| { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - type_.hash_stable(hcx, &mut hasher); - }); - }); - let unique_type_id = hasher.finish::().to_hex(); - - let key = self.unique_id_interner.intern(&unique_type_id); - self.type_to_unique_id.insert(type_, key); - - key - } - - /// Gets the `UniqueTypeId` for an enum variant. Enum variants are not really - /// types of their own, so they need special handling. We still need a - /// `UniqueTypeId` for them, since to debuginfo they *are* real types. - fn get_unique_type_id_of_enum_variant<'a>( - &mut self, - cx: &CodegenCx<'a, 'tcx>, - enum_type: Ty<'tcx>, - variant_name: &str, - ) -> UniqueTypeId { - let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type); - let enum_variant_type_id = - format!("{}::{}", self.get_unique_type_id_as_string(enum_type_id), variant_name); - let interner_key = self.unique_id_interner.intern(&enum_variant_type_id); - interner_key - } - - /// Gets the unique type ID string for an enum variant part. - /// Variant parts are not types and shouldn't really have their own ID, - /// but it makes `set_members_of_composite_type()` simpler. - fn get_unique_type_id_str_of_enum_variant_part( - &mut self, - enum_type_id: UniqueTypeId, - ) -> String { - format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)) - } - - /// Gets the `UniqueTypeId` for the type of a vtable. - fn get_unique_type_id_of_vtable_type(&mut self, vtable_type_name: &str) -> UniqueTypeId { - let interner_key = self.unique_id_interner.intern(vtable_type_name); - interner_key + fn find_metadata_for_unique_id( + &self, + unique_type_id: UniqueTypeId<'tcx>, + ) -> Option<&'ll DIType> { + self.unique_id_to_metadata.borrow().get(&unique_type_id).cloned() } } @@ -293,7 +226,7 @@ impl<'ll, 'tcx> TypeMap<'ll, 'tcx> { enum RecursiveTypeDescription<'ll, 'tcx> { UnfinishedMetadata { unfinished_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, metadata_stub: &'ll DICompositeType, member_holding_stub: &'ll DICompositeType, member_description_factory: MemberDescriptionFactory<'ll, 'tcx>, @@ -304,15 +237,13 @@ enum RecursiveTypeDescription<'ll, 'tcx> { fn create_and_register_recursive_type_forward_declaration<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unfinished_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, metadata_stub: &'ll DICompositeType, member_holding_stub: &'ll DICompositeType, member_description_factory: MemberDescriptionFactory<'ll, 'tcx>, ) -> RecursiveTypeDescription<'ll, 'tcx> { // Insert the stub into the `TypeMap` in order to allow for recursive references. - let mut type_map = debug_context(cx).type_map.borrow_mut(); - type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub); - type_map.register_type_with_metadata(unfinished_type, metadata_stub); + debug_context(cx).type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub); UnfinishedMetadata { unfinished_type, @@ -344,9 +275,10 @@ impl<'ll, 'tcx> RecursiveTypeDescription<'ll, 'tcx> { // `create_and_register_recursive_type_forward_declaration()` // function. { - let type_map = debug_context(cx).type_map.borrow(); - if type_map.find_metadata_for_unique_id(unique_type_id).is_none() - || type_map.find_metadata_for_type(unfinished_type).is_none() + if debug_context(cx) + .type_map + .find_metadata_for_unique_id(unique_type_id) + .is_none() { bug!( "Forward declaration of potentially recursive type \ @@ -379,7 +311,7 @@ impl<'ll, 'tcx> RecursiveTypeDescription<'ll, 'tcx> { macro_rules! return_if_metadata_created_in_meantime { ($cx: expr, $unique_type_id: expr) => { if let Some(metadata) = - debug_context($cx).type_map.borrow().find_metadata_for_unique_id($unique_type_id) + debug_context($cx).type_map.find_metadata_for_unique_id($unique_type_id) { return MetadataCreationResult::new(metadata, true); } @@ -390,7 +322,7 @@ macro_rules! return_if_metadata_created_in_meantime { /// For slices (that is, "arrays" of unknown size) use [slice_type_metadata]. fn fixed_size_array_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, array_type: Ty<'tcx>, ) -> MetadataCreationResult<'ll> { let ty::Array(element_type, len) = array_type.kind() else { @@ -434,7 +366,7 @@ fn pointer_or_reference_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ptr_type: Ty<'tcx>, pointee_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, ) -> MetadataCreationResult<'ll> { let pointee_type_metadata = type_metadata(cx, pointee_type); @@ -534,16 +466,42 @@ fn pointer_or_reference_metadata<'ll, 'tcx>( fn subroutine_type_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - unique_type_id: UniqueTypeId, - signature: ty::PolyFnSig<'tcx>, + unique_type_id: UniqueTypeId<'tcx>, ) -> MetadataCreationResult<'ll> { - let signature = - cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), signature); + // It's possible to create a self-referential + // type in Rust by using 'impl trait': + // + // fn foo() -> impl Copy { foo } + // + // Unfortunately LLVM's API does not allow us to create recursive subroutine types. + // In order to work around that restriction we place a marker type in the type map, + // before creating the actual type. If the actual type is recursive, it will hit the + // marker type. So we end up with a type that looks like + // + // fn foo() -> + // + // Once that is created, we replace the marker in the typemap with the actual type. + debug_context(cx) + .type_map + .unique_id_to_metadata + .borrow_mut() + .insert(unique_type_id, recursion_marker_type(cx)); + + let UniqueTypeId::Ty(fn_ty, _) = unique_type_id else { + bug!("subroutine_type_metadata() called with unexpected input type: {:?}", unique_type_id) + }; - let signature_metadata: Vec<_> = iter::once( + let signature = cx + .tcx + .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), fn_ty.fn_sig(cx.tcx)); + + let signature_metadata: SmallVec<[_; 32]> = iter::once( // return type match signature.output().kind() { - ty::Tuple(tys) if tys.is_empty() => None, + ty::Tuple(tys) if tys.is_empty() => { + // this is a "void" function + None + } _ => Some(type_metadata(cx, signature.output())), }, ) @@ -553,17 +511,30 @@ fn subroutine_type_metadata<'ll, 'tcx>( ) .collect(); - return_if_metadata_created_in_meantime!(cx, unique_type_id); + debug_context(cx).type_map.unique_id_to_metadata.borrow_mut().remove(&unique_type_id); - MetadataCreationResult::new( - unsafe { - llvm::LLVMRustDIBuilderCreateSubroutineType( - DIB(cx), - create_DIArray(DIB(cx), &signature_metadata[..]), - ) - }, - false, - ) + let fn_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateSubroutineType( + DIB(cx), + create_DIArray(DIB(cx), &signature_metadata[..]), + ) + }; + + // This is actually a function pointer, so wrap it in pointer DI. + let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false); + let metadata = unsafe { + llvm::LLVMRustDIBuilderCreatePointerType( + DIB(cx), + fn_metadata, + cx.tcx.data_layout.pointer_size.bits(), + cx.tcx.data_layout.pointer_align.abi.bits() as u32, + 0, // Ignore DWARF address space. + name.as_ptr().cast(), + name.len(), + ) + }; + + MetadataCreationResult::new(metadata, false) } /// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs @@ -571,7 +542,7 @@ fn subroutine_type_metadata<'ll, 'tcx>( fn dyn_type_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, dyn_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, ) -> &'ll DIType { if let ty::Dynamic(..) = dyn_type.kind() { let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true); @@ -601,7 +572,7 @@ fn dyn_type_metadata<'ll, 'tcx>( fn slice_type_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, slice_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, ) -> MetadataCreationResult<'ll> { let element_type = match slice_type.kind() { ty::Slice(element_type) => *element_type, @@ -620,38 +591,11 @@ fn slice_type_metadata<'ll, 'tcx>( } pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { - // Get the unique type ID of this type. - let unique_type_id = { - let mut type_map = debug_context(cx).type_map.borrow_mut(); - // First, try to find the type in `TypeMap`. If we have seen it before, we - // can exit early here. - match type_map.find_metadata_for_type(t) { - Some(metadata) => { - return metadata; - } - None => { - // The Ty is not in the `TypeMap` but maybe we have already seen - // an equivalent type (e.g., only differing in region arguments). - // In order to find out, generate the unique type ID and look - // that up. - let unique_type_id = type_map.get_unique_type_id_of_type(cx, t); - match type_map.find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => { - // There is already an equivalent type in the TypeMap. - // Register this Ty as an alias in the cache and - // return the cached metadata. - type_map.register_type_with_metadata(t, metadata); - return metadata; - } - None => { - // There really is no type metadata for this type, so - // proceed by creating it. - unique_type_id - } - } - } - } - }; + let unique_type_id = UniqueTypeId::for_ty(cx.tcx, t); + + if let Some(metadata) = debug_context(cx).type_map.find_metadata_for_unique_id(unique_type_id) { + return metadata; + } debug!("type_metadata: {:?}", t); @@ -676,64 +620,7 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll ty::Adt(def, _) if def.is_box() => { pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id) } - ty::FnDef(..) | ty::FnPtr(_) => { - if let Some(metadata) = - debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) - { - return metadata; - } - - // It's possible to create a self-referential - // type in Rust by using 'impl trait': - // - // fn foo() -> impl Copy { foo } - // - // See `TypeMap::remove_type` for more detals - // about the workaround. - - let temp_type = { - unsafe { - // The choice of type here is pretty arbitrary - - // anything reading the debuginfo for a recursive - // type is going to see *something* weird - the only - // question is what exactly it will see. - let name = ""; - llvm::LLVMRustDIBuilderCreateBasicType( - DIB(cx), - name.as_ptr().cast(), - name.len(), - cx.size_of(t).bits(), - DW_ATE_unsigned, - ) - } - }; - - let type_map = &debug_context(cx).type_map; - type_map.borrow_mut().register_type_with_metadata(t, temp_type); - - let fn_metadata = - subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx)).metadata; - - type_map.borrow_mut().remove_type(t); - - // This is actually a function pointer, so wrap it in pointer DI. - let (pointer_size, pointer_align) = - cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.mk_unit())); - let name = compute_debuginfo_type_name(cx.tcx, t, false); - let md = unsafe { - llvm::LLVMRustDIBuilderCreatePointerType( - DIB(cx), - fn_metadata, - pointer_size.bits(), - pointer_align.bits() as u32, - 0, // Ignore DWARF address space. - name.as_ptr().cast(), - name.len(), - ) - }; - - MetadataCreationResult::new(md, false) - } + ty::FnDef(..) | ty::FnPtr(_) => subroutine_type_metadata(cx, unique_type_id), ty::Closure(def_id, substs) => { let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect(); let containing_scope = get_namespace_for_item(cx, def_id); @@ -764,47 +651,56 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll }; { - let mut type_map = debug_context(cx).type_map.borrow_mut(); - if already_stored_in_typemap { - // Also make sure that we already have a `TypeMap` entry for the unique type ID. - let Some(metadata_for_uid) = type_map.find_metadata_for_unique_id(unique_type_id) else { - bug!( - "expected type metadata for unique \ - type ID '{}' to already be in \ - the `debuginfo::TypeMap` but it \ - was not. (Ty = {})", - type_map.get_unique_type_id_as_string(unique_type_id), - t - ); - }; - - match type_map.find_metadata_for_type(t) { - Some(metadata) => { - if metadata != metadata_for_uid { + // Make sure that we really do have a `TypeMap` entry for the unique type ID. + let metadata_for_uid = + match debug_context(cx).type_map.find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => metadata, + None => { bug!( - "mismatch between `Ty` and \ - `UniqueTypeId` maps in \ - `debuginfo::TypeMap`. \ - UniqueTypeId={}, Ty={}", - type_map.get_unique_type_id_as_string(unique_type_id), - t + "expected type metadata for unique \ + type ID '{:?}' to already be in \ + the `debuginfo::TypeMap` but it \ + was not.", + unique_type_id, ); } - } - None => { - type_map.register_type_with_metadata(t, metadata); - } - } + }; + + debug_assert_eq!(metadata_for_uid as *const _, metadata as *const _); } else { - type_map.register_type_with_metadata(t, metadata); - type_map.register_unique_id_with_metadata(unique_type_id, metadata); + debug_context(cx).type_map.register_unique_id_with_metadata(unique_type_id, metadata); } } metadata } +fn recursion_marker_type<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll DIType { + *debug_context(cx).recursion_marker_type.get_or_init(move || { + unsafe { + // The choice of type here is pretty arbitrary - + // anything reading the debuginfo for a recursive + // type is going to see *something* weird - the only + // question is what exactly it will see. + // + // FIXME: the name `` does not fit the naming scheme + // of other types. + // + // FIXME: it might make sense to use an actual pointer type here + // so that debuggers can show the address. + let name = ""; + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr().cast(), + name.len(), + cx.tcx.data_layout.pointer_size.bits(), + DW_ATE_unsigned, + ) + } + }) +} + fn hex_encode(data: &[u8]) -> String { let mut hex_string = String::with_capacity(data.len() * 2); for byte in data.iter() { @@ -985,7 +881,7 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l fn foreign_type_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, ) -> &'ll DIType { debug!("foreign_type_metadata: {:?}", t); @@ -1306,7 +1202,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { fn prepare_struct_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, struct_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, ) -> RecursiveTypeDescription<'ll, 'tcx> { let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false); @@ -1415,7 +1311,7 @@ fn prepare_tuple_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, tuple_type: Ty<'tcx>, component_types: &[Ty<'tcx>], - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, containing_scope: Option<&'ll DIScope>, ) -> RecursiveTypeDescription<'ll, 'tcx> { let (size, align) = cx.size_and_align_of(tuple_type); @@ -1483,7 +1379,7 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> { fn prepare_union_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, union_type: Ty<'tcx>, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, ) -> RecursiveTypeDescription<'ll, 'tcx> { let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false); @@ -1570,7 +1466,7 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { }; let variant_info_for = |index: VariantIdx| match *self.enum_type.kind() { - ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]), + ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index], index), ty::Generator(def_id, _, _) => { let (generator_layout, generator_saved_local_names) = generator_variant_info_data.as_ref().unwrap(); @@ -1913,7 +1809,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> { #[derive(Copy, Clone)] enum VariantInfo<'a, 'tcx> { - Adt(&'tcx ty::VariantDef), + Adt(&'tcx ty::VariantDef, VariantIdx), Generator { def_id: DefId, generator_layout: &'tcx GeneratorLayout<'tcx>, @@ -1923,9 +1819,17 @@ enum VariantInfo<'a, 'tcx> { } impl<'tcx> VariantInfo<'_, 'tcx> { + fn variant_idx(&self) -> VariantIdx { + match self { + VariantInfo::Adt(_, variant_index) | VariantInfo::Generator { variant_index, .. } => { + *variant_index + } + } + } + fn map_struct_name(&self, f: impl FnOnce(&str) -> R) -> R { match self { - VariantInfo::Adt(variant) => f(variant.name.as_str()), + VariantInfo::Adt(variant, _) => f(variant.name.as_str()), VariantInfo::Generator { variant_index, .. } => { f(&GeneratorSubsts::variant_name(*variant_index)) } @@ -1934,7 +1838,7 @@ impl<'tcx> VariantInfo<'_, 'tcx> { fn variant_name(&self) -> String { match self { - VariantInfo::Adt(variant) => variant.name.to_string(), + VariantInfo::Adt(variant, _) => variant.name.to_string(), VariantInfo::Generator { variant_index, .. } => { // Since GDB currently prints out the raw discriminant along // with every variant, make each variant name be just the value @@ -1947,7 +1851,7 @@ impl<'tcx> VariantInfo<'_, 'tcx> { fn field_name(&self, i: usize) -> String { let field_name = match *self { - VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn => { + VariantInfo::Adt(variant, _) if variant.ctor_kind != CtorKind::Fn => { Some(variant.fields[i].name) } VariantInfo::Generator { @@ -1988,10 +1892,8 @@ fn describe_enum_variant<'ll, 'tcx>( containing_scope: &'ll DIScope, ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { let metadata_stub = variant.map_struct_name(|variant_name| { - let unique_type_id = debug_context(cx) - .type_map - .borrow_mut() - .get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name); + let unique_type_id = + UniqueTypeId::for_enum_variant(cx.tcx, layout.ty, variant.variant_idx()); let (size, align) = cx.size_and_align_of(layout.ty); @@ -2021,7 +1923,7 @@ fn prepare_enum_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, enum_type: Ty<'tcx>, enum_def_id: DefId, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, outer_field_tys: Vec>, ) -> RecursiveTypeDescription<'ll, 'tcx> { let tcx = cx.tcx; @@ -2145,8 +2047,7 @@ fn prepare_enum_metadata<'ll, 'tcx>( }; let enum_metadata = { - let type_map = debug_context(cx).type_map.borrow(); - let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); + let unique_type_id_str = unique_type_id.generate_unique_id_string(tcx); unsafe { llvm::LLVMRustDIBuilderCreateUnionType( @@ -2257,10 +2158,9 @@ fn prepare_enum_metadata<'ll, 'tcx>( } }; - let variant_part_unique_type_id_str = debug_context(cx) - .type_map - .borrow_mut() - .get_unique_type_id_str_of_enum_variant_part(unique_type_id); + let variant_part_unique_type_id_str = + UniqueTypeId::for_enum_variant_part(tcx, enum_type).generate_unique_id_string(tcx); + let empty_array = create_DIArray(DIB(cx), &[]); let name = ""; let variant_part = unsafe { @@ -2288,9 +2188,7 @@ fn prepare_enum_metadata<'ll, 'tcx>( // an equivalent layout but offers us much better integration with // debuggers. let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]); - - let type_map = debug_context(cx).type_map.borrow(); - let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); + let unique_type_id_str = unique_type_id.generate_unique_id_string(tcx); unsafe { llvm::LLVMRustDIBuilderCreateStructType( @@ -2336,7 +2234,7 @@ fn composite_type_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, composite_type: Ty<'tcx>, composite_type_name: &str, - composite_type_unique_id: UniqueTypeId, + composite_type_unique_id: UniqueTypeId<'tcx>, member_descriptions: Vec>, containing_scope: Option<&'ll DIScope>, ) -> &'ll DICompositeType { @@ -2459,13 +2357,12 @@ fn create_struct_stub<'ll, 'tcx>( size: Size, align: Align, type_name: &str, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, containing_scope: Option<&'ll DIScope>, flags: DIFlags, vtable_holder: Option<&'ll DIType>, ) -> &'ll DICompositeType { - let type_map = debug_context(cx).type_map.borrow(); - let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); + let unique_type_id = unique_type_id.generate_unique_id_string(cx.tcx); let metadata_stub = unsafe { // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null @@ -2499,13 +2396,11 @@ fn create_union_stub<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, union_type: Ty<'tcx>, union_type_name: &str, - unique_type_id: UniqueTypeId, + unique_type_id: UniqueTypeId<'tcx>, containing_scope: &'ll DIScope, ) -> &'ll DICompositeType { let (union_size, union_align) = cx.size_and_align_of(union_type); - - let type_map = debug_context(cx).type_map.borrow(); - let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); + let unique_type_id = unique_type_id.generate_unique_id_string(cx.tcx); let metadata_stub = unsafe { // `LLVMRustDIBuilderCreateUnionType()` wants an empty array. A null @@ -2629,10 +2524,7 @@ fn vtable_type_metadata<'ll, 'tcx>( let vtable_type_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type); - let unique_type_id = debug_context(cx) - .type_map - .borrow_mut() - .get_unique_type_id_of_vtable_type(&vtable_type_name); + let unique_type_id = UniqueTypeId::for_vtable_ty(tcx, ty, poly_trait_ref); let size = pointer_size * vtable_entries.len() as u64; // This gets mapped to a DW_AT_containing_type attribute which allows GDB to correlate diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 247cb9ee6e8c9..1b4a193dbf185 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -38,6 +38,7 @@ use libc::c_uint; use smallvec::SmallVec; use std::cell::RefCell; use std::iter; +use std::lazy::OnceCell; use tracing::debug; mod create_scope_map; @@ -63,9 +64,11 @@ pub struct CrateDebugContext<'a, 'tcx> { created_files: RefCell, Option), &'a DIFile>>, created_enum_disr_types: RefCell>, - type_map: RefCell>, + type_map: TypeMap<'a, 'tcx>, namespace_map: RefCell>, + recursion_marker_type: OnceCell<&'a DIType>, + // This collection is used to assert that composite types (structs, enums, // ...) have their members only set once: composite_types_completed: RefCell>, @@ -93,6 +96,7 @@ impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> { created_enum_disr_types: Default::default(), type_map: Default::default(), namespace_map: RefCell::new(Default::default()), + recursion_marker_type: OnceCell::new(), composite_types_completed: Default::default(), } } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 75836e143856f..d39e753b8f3a3 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -9,10 +9,14 @@ #![feature(crate_visibility_modifier)] #![feature(let_else)] #![feature(extern_types)] +#![feature(once_cell)] #![feature(nll)] #![recursion_limit = "256"] #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] +#[macro_use] +extern crate rustc_macros; + use back::write::{create_informational_target_machine, create_target_machine}; pub use llvm_util::target_features; diff --git a/src/test/codegen/fn-impl-trait-self.rs b/src/test/codegen/fn-impl-trait-self.rs index 4bd811bed10e5..0abc8a409ed7a 100644 --- a/src/test/codegen/fn-impl-trait-self.rs +++ b/src/test/codegen/fn-impl-trait-self.rs @@ -5,7 +5,7 @@ // NONMSVC: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> ",{{.*}} // // CHECK: {{.*}}DISubroutineType{{.*}} -// CHECK: {{.*}}DIBasicType(name: "", encoding: DW_ATE_unsigned) +// CHECK: {{.*}}DIBasicType(name: "", size: {{32|64}}, encoding: DW_ATE_unsigned) pub fn foo() -> impl Copy { foo