rustc_codegen_llvm/debuginfo/metadata/
type_map.rs

1use std::cell::RefCell;
2
3use rustc_abi::{Align, Size, VariantIdx};
4use rustc_data_structures::fingerprint::Fingerprint;
5use rustc_data_structures::fx::FxHashMap;
6use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
7use rustc_macros::HashStable;
8use rustc_middle::bug;
9use rustc_middle::ty::{self, ExistentialTraitRef, Ty, TyCtxt};
10
11use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
12use crate::common::{AsCCharPtr, CodegenCx};
13use crate::debuginfo::utils::{DIB, create_DIArray, debug_context};
14use crate::llvm::debuginfo::{DIFlags, DIScope, DIType};
15use crate::llvm::{self};
16
17mod private {
18    use rustc_macros::HashStable;
19
20    // This type cannot be constructed outside of this module because
21    // it has a private field. We make use of this in order to prevent
22    // `UniqueTypeId` from being constructed directly, without asserting
23    // the preconditions.
24    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)]
25    pub(crate) struct HiddenZst;
26}
27
28/// A unique identifier for anything that we create a debuginfo node for.
29/// The types it contains are expected to already be normalized (which
30/// is asserted in the constructors).
31///
32/// Note that there are some things that only show up in debuginfo, like
33/// the separate type descriptions for each enum variant. These get an ID
34/// too because they have their own debuginfo node in LLVM IR.
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)]
36pub(super) enum UniqueTypeId<'tcx> {
37    /// The ID of a regular type as it shows up at the language level.
38    Ty(Ty<'tcx>, private::HiddenZst),
39    /// The ID for the single DW_TAG_variant_part nested inside the top-level
40    /// DW_TAG_structure_type that describes enums and coroutines.
41    VariantPart(Ty<'tcx>, private::HiddenZst),
42    /// The ID for the artificial struct type describing a single enum variant.
43    VariantStructType(Ty<'tcx>, VariantIdx, private::HiddenZst),
44    /// The ID for the additional wrapper struct type describing an enum variant in CPP-like mode.
45    VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst),
46    /// The ID of the artificial type we create for VTables.
47    VTableTy(Ty<'tcx>, Option<ExistentialTraitRef<'tcx>>, private::HiddenZst),
48}
49
50impl<'tcx> UniqueTypeId<'tcx> {
51    pub(crate) fn for_ty(tcx: TyCtxt<'tcx>, t: Ty<'tcx>) -> Self {
52        assert_eq!(t, tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), t));
53        UniqueTypeId::Ty(t, private::HiddenZst)
54    }
55
56    pub(crate) fn for_enum_variant_part(tcx: TyCtxt<'tcx>, enum_ty: Ty<'tcx>) -> Self {
57        assert_eq!(
58            enum_ty,
59            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
60        );
61        UniqueTypeId::VariantPart(enum_ty, private::HiddenZst)
62    }
63
64    pub(crate) fn for_enum_variant_struct_type(
65        tcx: TyCtxt<'tcx>,
66        enum_ty: Ty<'tcx>,
67        variant_idx: VariantIdx,
68    ) -> Self {
69        assert_eq!(
70            enum_ty,
71            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
72        );
73        UniqueTypeId::VariantStructType(enum_ty, variant_idx, private::HiddenZst)
74    }
75
76    pub(crate) fn for_enum_variant_struct_type_wrapper(
77        tcx: TyCtxt<'tcx>,
78        enum_ty: Ty<'tcx>,
79        variant_idx: VariantIdx,
80    ) -> Self {
81        assert_eq!(
82            enum_ty,
83            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
84        );
85        UniqueTypeId::VariantStructTypeCppLikeWrapper(enum_ty, variant_idx, private::HiddenZst)
86    }
87
88    pub(crate) fn for_vtable_ty(
89        tcx: TyCtxt<'tcx>,
90        self_type: Ty<'tcx>,
91        implemented_trait: Option<ExistentialTraitRef<'tcx>>,
92    ) -> Self {
93        assert_eq!(
94            self_type,
95            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), self_type)
96        );
97        assert_eq!(
98            implemented_trait,
99            tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), implemented_trait)
100        );
101        UniqueTypeId::VTableTy(self_type, implemented_trait, private::HiddenZst)
102    }
103
104    /// Generates a string version of this [UniqueTypeId], which can be used as the `UniqueId`
105    /// argument of the various `LLVMRustDIBuilderCreate*Type()` methods.
106    ///
107    /// Right now this takes the form of a hex-encoded opaque hash value.
108    fn generate_unique_id_string(self, tcx: TyCtxt<'tcx>) -> String {
109        let mut hasher = StableHasher::new();
110        tcx.with_stable_hashing_context(|mut hcx| {
111            hcx.while_hashing_spans(false, |hcx| self.hash_stable(hcx, &mut hasher))
112        });
113        hasher.finish::<Fingerprint>().to_hex()
114    }
115
116    pub(crate) fn expect_ty(self) -> Ty<'tcx> {
117        match self {
118            UniqueTypeId::Ty(ty, _) => ty,
119            _ => bug!("Expected `UniqueTypeId::Ty` but found `{:?}`", self),
120        }
121    }
122}
123
124/// The `TypeMap` is where the debug context holds the type metadata nodes
125/// created so far. The debuginfo nodes are identified by `UniqueTypeId`.
126#[derive(Default)]
127pub(crate) struct TypeMap<'ll, 'tcx> {
128    pub(super) unique_id_to_di_node: RefCell<FxHashMap<UniqueTypeId<'tcx>, &'ll DIType>>,
129}
130
131impl<'ll, 'tcx> TypeMap<'ll, 'tcx> {
132    /// Adds a `UniqueTypeId` to metadata mapping to the `TypeMap`. The method will
133    /// fail if the mapping already exists.
134    pub(super) fn insert(&self, unique_type_id: UniqueTypeId<'tcx>, metadata: &'ll DIType) {
135        if self.unique_id_to_di_node.borrow_mut().insert(unique_type_id, metadata).is_some() {
136            bug!("type metadata for unique ID '{:?}' is already in the `TypeMap`!", unique_type_id);
137        }
138    }
139
140    pub(super) fn di_node_for_unique_id(
141        &self,
142        unique_type_id: UniqueTypeId<'tcx>,
143    ) -> Option<&'ll DIType> {
144        self.unique_id_to_di_node.borrow().get(&unique_type_id).cloned()
145    }
146}
147
148pub(crate) struct DINodeCreationResult<'ll> {
149    pub di_node: &'ll DIType,
150    pub already_stored_in_typemap: bool,
151}
152
153impl<'ll> DINodeCreationResult<'ll> {
154    pub(crate) fn new(di_node: &'ll DIType, already_stored_in_typemap: bool) -> Self {
155        DINodeCreationResult { di_node, already_stored_in_typemap }
156    }
157}
158
159#[derive(Debug, Copy, Clone, Eq, PartialEq)]
160pub(crate) enum Stub<'ll> {
161    Struct,
162    Union,
163    VTableTy { vtable_holder: &'ll DIType },
164}
165
166pub(crate) struct StubInfo<'ll, 'tcx> {
167    metadata: &'ll DIType,
168    unique_type_id: UniqueTypeId<'tcx>,
169}
170
171impl<'ll, 'tcx> StubInfo<'ll, 'tcx> {
172    pub(super) fn new(
173        cx: &CodegenCx<'ll, 'tcx>,
174        unique_type_id: UniqueTypeId<'tcx>,
175        build: impl FnOnce(&CodegenCx<'ll, 'tcx>, /* unique_type_id_str: */ &str) -> &'ll DIType,
176    ) -> StubInfo<'ll, 'tcx> {
177        let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx);
178        let di_node = build(cx, &unique_type_id_str);
179        StubInfo { metadata: di_node, unique_type_id }
180    }
181}
182
183/// Create a stub debuginfo node onto which fields and nested types can be attached.
184pub(super) fn stub<'ll, 'tcx>(
185    cx: &CodegenCx<'ll, 'tcx>,
186    kind: Stub<'ll>,
187    unique_type_id: UniqueTypeId<'tcx>,
188    name: &str,
189    def_location: Option<DefinitionLocation<'ll>>,
190    (size, align): (Size, Align),
191    containing_scope: Option<&'ll DIScope>,
192    flags: DIFlags,
193) -> StubInfo<'ll, 'tcx> {
194    let empty_array = create_DIArray(DIB(cx), &[]);
195    let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx);
196
197    let (file_metadata, line_number) = if let Some(def_location) = def_location {
198        (def_location.0, def_location.1)
199    } else {
200        (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
201    };
202
203    let metadata = match kind {
204        Stub::Struct | Stub::VTableTy { .. } => {
205            let vtable_holder = match kind {
206                Stub::VTableTy { vtable_holder } => Some(vtable_holder),
207                _ => None,
208            };
209            unsafe {
210                llvm::LLVMRustDIBuilderCreateStructType(
211                    DIB(cx),
212                    containing_scope,
213                    name.as_c_char_ptr(),
214                    name.len(),
215                    file_metadata,
216                    line_number,
217                    size.bits(),
218                    align.bits() as u32,
219                    flags,
220                    None,
221                    empty_array,
222                    0,
223                    vtable_holder,
224                    unique_type_id_str.as_c_char_ptr(),
225                    unique_type_id_str.len(),
226                )
227            }
228        }
229        Stub::Union => unsafe {
230            llvm::LLVMRustDIBuilderCreateUnionType(
231                DIB(cx),
232                containing_scope,
233                name.as_c_char_ptr(),
234                name.len(),
235                file_metadata,
236                line_number,
237                size.bits(),
238                align.bits() as u32,
239                flags,
240                Some(empty_array),
241                0,
242                unique_type_id_str.as_c_char_ptr(),
243                unique_type_id_str.len(),
244            )
245        },
246    };
247    StubInfo { metadata, unique_type_id }
248}
249
250/// This function enables creating debuginfo nodes that can recursively refer to themselves.
251/// It will first insert the given stub into the type map and only then execute the `members`
252/// and `generics` closures passed in. These closures have access to the stub so they can
253/// directly attach fields to them. If the type of a field transitively refers back
254/// to the type currently being built, the stub will already be found in the type map,
255/// which effectively breaks the recursion cycle.
256pub(super) fn build_type_with_children<'ll, 'tcx>(
257    cx: &CodegenCx<'ll, 'tcx>,
258    stub_info: StubInfo<'ll, 'tcx>,
259    members: impl FnOnce(&CodegenCx<'ll, 'tcx>, &'ll DIType) -> SmallVec<&'ll DIType>,
260    generics: impl FnOnce(&CodegenCx<'ll, 'tcx>) -> SmallVec<Option<&'ll DIType>>,
261) -> DINodeCreationResult<'ll> {
262    assert_eq!(debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None);
263
264    debug_context(cx).type_map.insert(stub_info.unique_type_id, stub_info.metadata);
265
266    let members: SmallVec<_> =
267        members(cx, stub_info.metadata).into_iter().map(|node| Some(node)).collect();
268    let generics = generics(cx);
269
270    if !(members.is_empty() && generics.is_empty()) {
271        unsafe {
272            let members_array = create_DIArray(DIB(cx), &members[..]);
273            let generics_array = create_DIArray(DIB(cx), &generics[..]);
274            llvm::LLVMRustDICompositeTypeReplaceArrays(
275                DIB(cx),
276                stub_info.metadata,
277                Some(members_array),
278                Some(generics_array),
279            );
280        }
281    }
282
283    DINodeCreationResult { di_node: stub_info.metadata, already_stored_in_typemap: true }
284}