about summary refs log tree commit diff
path: root/compiler/rustc_codegen_llvm/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_llvm/src')
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs41
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs597
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs33
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs4
5 files changed, 290 insertions, 391 deletions
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 51223697dbd..c98720944c9 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -2,6 +2,7 @@ use crate::base;
 use crate::common::CodegenCx;
 use crate::debuginfo;
 use crate::llvm::{self, True};
+use crate::llvm_util;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
@@ -37,7 +38,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) ->
         alloc: &'a Allocation,
         range: Range<usize>,
     ) {
-        let mut chunks = alloc
+        let chunks = alloc
             .init_mask()
             .range_as_init_chunks(Size::from_bytes(range.start), Size::from_bytes(range.end));
 
@@ -53,30 +54,26 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) ->
             }
         };
 
-        // Generating partially-uninit consts inhibits optimizations, so it is disabled by default.
-        // See https://github.com/rust-lang/rust/issues/84565.
-        let allow_partially_uninit =
-            match cx.sess().opts.debugging_opts.partially_uninit_const_threshold {
-                Some(max) => range.len() <= max,
-                None => false,
-            };
+        // Generating partially-uninit consts is limited to small numbers of chunks,
+        // to avoid the cost of generating large complex const expressions.
+        // For example, `[(u32, u8); 1024 * 1024]` contains uninit padding in each element,
+        // and would result in `{ [5 x i8] zeroinitializer, [3 x i8] undef, ...repeat 1M times... }`.
+        let max = if llvm_util::get_version() < (14, 0, 0) {
+            // Generating partially-uninit consts inhibits optimizations in LLVM < 14.
+            // See https://github.com/rust-lang/rust/issues/84565.
+            1
+        } else {
+            cx.sess().opts.debugging_opts.uninit_const_chunk_threshold
+        };
+        let allow_uninit_chunks = chunks.clone().take(max.saturating_add(1)).count() <= max;
 
-        if allow_partially_uninit {
+        if allow_uninit_chunks {
             llvals.extend(chunks.map(chunk_to_llval));
         } else {
-            let llval = match (chunks.next(), chunks.next()) {
-                (Some(chunk), None) => {
-                    // exactly one chunk, either fully init or fully uninit
-                    chunk_to_llval(chunk)
-                }
-                _ => {
-                    // partially uninit, codegen as if it was initialized
-                    // (using some arbitrary value for uninit bytes)
-                    let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
-                    cx.const_bytes(bytes)
-                }
-            };
-            llvals.push(llval);
+            // If this allocation contains any uninit bytes, codegen as if it was initialized
+            // (using some arbitrary value for uninit bytes).
+            let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
+            llvals.push(cx.const_bytes(bytes));
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 4ca92b3efe0..89fc8980037 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<PolyExistentialTraitRef<'tcx>>, 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<PolyExistentialTraitRef<'tcx>>,
+        ) -> 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::<Fingerprint>().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<UniqueTypeId, &'ll DIType>,
-    /// A map from types to debuginfo metadata. This is an N:1 mapping.
-    type_to_metadata: FxHashMap<Ty<'tcx>, &'ll DIType>,
-    /// A map from types to `UniqueTypeId`. This is an N:1 mapping.
-    type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>,
+    unique_id_to_metadata: RefCell<FxHashMap<UniqueTypeId<'tcx>, &'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::<Fingerprint>().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);
 
@@ -449,7 +381,10 @@ fn pointer_or_reference_metadata<'ll, 'tcx>(
             // This is a thin pointer. Create a regular pointer type and give it the correct name.
             debug_assert_eq!(
                 (thin_pointer_size, thin_pointer_align),
-                cx.size_and_align_of(ptr_type)
+                cx.size_and_align_of(ptr_type),
+                "ptr_type={}, pointee_type={}",
+                ptr_type,
+                pointee_type,
             );
 
             unsafe {
@@ -531,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() -> <recursive_type>
+    //
+    // 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 signature_metadata: Vec<_> = iter::once(
+    let UniqueTypeId::Ty(fn_ty, _) = unique_type_id else {
+        bug!("subroutine_type_metadata() called with unexpected input type: {:?}", unique_type_id)
+    };
+
+    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())),
         },
     )
@@ -550,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
@@ -568,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);
@@ -598,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,
@@ -617,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);
 
@@ -673,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 = "<recur_type>";
-                    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);
@@ -761,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 `<recur_type>` 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 = "<recur_type>";
+            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() {
@@ -982,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);
 
@@ -1303,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);
 
@@ -1412,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);
@@ -1480,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);
 
@@ -1567,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();
@@ -1910,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>,
@@ -1920,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<R>(&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))
             }
@@ -1931,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
@@ -1944,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 {
@@ -1985,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);
 
@@ -2018,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<Ty<'tcx>>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tcx = cx.tcx;
@@ -2142,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(
@@ -2254,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 {
@@ -2285,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(
@@ -2333,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<MemberDescription<'ll>>,
     containing_scope: Option<&'ll DIScope>,
 ) -> &'ll DICompositeType {
@@ -2456,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
@@ -2496,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
@@ -2626,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 247cb9ee6e8..1b4a193dbf1 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<FxHashMap<(Option<String>, Option<String>), &'a DIFile>>,
     created_enum_disr_types: RefCell<FxHashMap<(DefId, Primitive), &'a DIType>>,
 
-    type_map: RefCell<TypeMap<'a, 'tcx>>,
+    type_map: TypeMap<'a, 'tcx>,
     namespace_map: RefCell<DefIdMap<&'a DIScope>>,
 
+    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<FxHashSet<&'a DIType>>,
@@ -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/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index acd032a7dc6..fa75463067f 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -4,9 +4,9 @@ use super::namespace::item_namespace;
 use super::CrateDebugContext;
 
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::ty::{self, DefIdTree, Ty};
-use rustc_target::abi::Variants;
+use tracing::trace;
 
 use crate::common::CodegenCx;
 use crate::llvm;
@@ -63,30 +63,26 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     pointee_ty: Ty<'tcx>,
 ) -> Option<FatPtrKind> {
-    let layout = cx.layout_of(pointee_ty);
+    let pointee_tail_ty = cx.tcx.struct_tail_erasing_lifetimes(pointee_ty, cx.param_env());
+    let layout = cx.layout_of(pointee_tail_ty);
+    trace!(
+        "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
+        pointee_tail_ty,
+        layout,
+        layout.is_unsized()
+    );
 
     if !layout.is_unsized() {
         return None;
     }
 
-    match *pointee_ty.kind() {
+    match *pointee_tail_ty.kind() {
         ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
         ty::Dynamic(..) => Some(FatPtrKind::Dyn),
-        ty::Adt(..) | ty::Tuple(..) if matches!(layout.variants, Variants::Single { .. }) => {
-            let last_field_index = layout.fields.count() - 1;
-            debug_assert!(
-                (0..last_field_index)
-                    .all(|field_index| { !layout.field(cx, field_index).is_unsized() })
-            );
-
-            let unsized_field = layout.field(cx, last_field_index);
-            debug_assert!(unsized_field.is_unsized());
-            fat_pointer_kind(cx, unsized_field.ty)
-        }
         ty::Foreign(_) => {
             // Assert that pointers to foreign types really are thin:
             debug_assert_eq!(
-                cx.size_of(cx.tcx.mk_imm_ptr(pointee_ty)),
+                cx.size_of(cx.tcx.mk_imm_ptr(pointee_tail_ty)),
                 cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8))
             );
             None
@@ -94,7 +90,10 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
         _ => {
             // For all other pointee types we should already have returned None
             // at the beginning of the function.
-            panic!("fat_pointer_kind() - Encountered unexpected `pointee_ty`: {:?}", pointee_ty)
+            panic!(
+                "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {:?}",
+                pointee_tail_ty
+            )
         }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 75836e14385..d39e753b8f3 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;