rustc_codegen_llvm/debuginfo/metadata/
type_map.rs1use std::cell::RefCell;
2
3use libc::c_uint;
4use rustc_abi::{Align, Size, VariantIdx};
5use rustc_data_structures::fingerprint::Fingerprint;
6use rustc_data_structures::fx::FxHashMap;
7use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
8use rustc_macros::HashStable;
9use rustc_middle::bug;
10use rustc_middle::ty::{self, ExistentialTraitRef, Ty, TyCtxt};
11
12use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
13use crate::common::CodegenCx;
14use crate::debuginfo::utils::{DIB, create_DIArray, debug_context};
15use crate::llvm::debuginfo::{DIFlags, DIScope, DIType};
16use crate::llvm::{self};
17
18mod private {
19 use rustc_macros::HashStable;
20
21 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)]
26 pub(crate) struct HiddenZst;
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)]
37pub(super) enum UniqueTypeId<'tcx> {
38 Ty(Ty<'tcx>, private::HiddenZst),
40 VariantPart(Ty<'tcx>, private::HiddenZst),
43 VariantStructType(Ty<'tcx>, VariantIdx, private::HiddenZst),
45 VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst),
47 VTableTy(Ty<'tcx>, Option<ExistentialTraitRef<'tcx>>, private::HiddenZst),
49}
50
51impl<'tcx> UniqueTypeId<'tcx> {
52 pub(crate) fn for_ty(tcx: TyCtxt<'tcx>, t: Ty<'tcx>) -> Self {
53 assert_eq!(t, tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), t));
54 UniqueTypeId::Ty(t, private::HiddenZst)
55 }
56
57 pub(crate) fn for_enum_variant_part(tcx: TyCtxt<'tcx>, enum_ty: Ty<'tcx>) -> Self {
58 assert_eq!(
59 enum_ty,
60 tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
61 );
62 UniqueTypeId::VariantPart(enum_ty, private::HiddenZst)
63 }
64
65 pub(crate) fn for_enum_variant_struct_type(
66 tcx: TyCtxt<'tcx>,
67 enum_ty: Ty<'tcx>,
68 variant_idx: VariantIdx,
69 ) -> Self {
70 assert_eq!(
71 enum_ty,
72 tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
73 );
74 UniqueTypeId::VariantStructType(enum_ty, variant_idx, private::HiddenZst)
75 }
76
77 pub(crate) fn for_enum_variant_struct_type_wrapper(
78 tcx: TyCtxt<'tcx>,
79 enum_ty: Ty<'tcx>,
80 variant_idx: VariantIdx,
81 ) -> Self {
82 assert_eq!(
83 enum_ty,
84 tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), enum_ty)
85 );
86 UniqueTypeId::VariantStructTypeCppLikeWrapper(enum_ty, variant_idx, private::HiddenZst)
87 }
88
89 pub(crate) fn for_vtable_ty(
90 tcx: TyCtxt<'tcx>,
91 self_type: Ty<'tcx>,
92 implemented_trait: Option<ExistentialTraitRef<'tcx>>,
93 ) -> Self {
94 assert_eq!(
95 self_type,
96 tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), self_type)
97 );
98 assert_eq!(
99 implemented_trait,
100 tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), implemented_trait)
101 );
102 UniqueTypeId::VTableTy(self_type, implemented_trait, private::HiddenZst)
103 }
104
105 fn generate_unique_id_string(self, tcx: TyCtxt<'tcx>) -> String {
110 let mut hasher = StableHasher::new();
111 tcx.with_stable_hashing_context(|mut hcx| {
112 hcx.while_hashing_spans(false, |hcx| self.hash_stable(hcx, &mut hasher))
113 });
114 hasher.finish::<Fingerprint>().to_hex()
115 }
116
117 pub(crate) fn expect_ty(self) -> Ty<'tcx> {
118 match self {
119 UniqueTypeId::Ty(ty, _) => ty,
120 _ => bug!("Expected `UniqueTypeId::Ty` but found `{:?}`", self),
121 }
122 }
123}
124
125#[derive(Default)]
128pub(crate) struct TypeMap<'ll, 'tcx> {
129 pub(super) unique_id_to_di_node: RefCell<FxHashMap<UniqueTypeId<'tcx>, &'ll DIType>>,
130}
131
132impl<'ll, 'tcx> TypeMap<'ll, 'tcx> {
133 pub(super) fn insert(&self, unique_type_id: UniqueTypeId<'tcx>, metadata: &'ll DIType) {
136 if self.unique_id_to_di_node.borrow_mut().insert(unique_type_id, metadata).is_some() {
137 bug!("type metadata for unique ID '{:?}' is already in the `TypeMap`!", unique_type_id);
138 }
139 }
140
141 pub(super) fn di_node_for_unique_id(
142 &self,
143 unique_type_id: UniqueTypeId<'tcx>,
144 ) -> Option<&'ll DIType> {
145 self.unique_id_to_di_node.borrow().get(&unique_type_id).cloned()
146 }
147}
148
149pub(crate) struct DINodeCreationResult<'ll> {
150 pub di_node: &'ll DIType,
151 pub already_stored_in_typemap: bool,
152}
153
154impl<'ll> DINodeCreationResult<'ll> {
155 pub(crate) fn new(di_node: &'ll DIType, already_stored_in_typemap: bool) -> Self {
156 DINodeCreationResult { di_node, already_stored_in_typemap }
157 }
158}
159
160#[derive(Debug, Copy, Clone, Eq, PartialEq)]
161pub(crate) enum Stub<'ll> {
162 Struct,
163 Union,
164 VTableTy { vtable_holder: &'ll DIType },
165}
166
167pub(crate) struct StubInfo<'ll, 'tcx> {
168 metadata: &'ll DIType,
169 unique_type_id: UniqueTypeId<'tcx>,
170}
171
172impl<'ll, 'tcx> StubInfo<'ll, 'tcx> {
173 pub(super) fn new(
174 cx: &CodegenCx<'ll, 'tcx>,
175 unique_type_id: UniqueTypeId<'tcx>,
176 build: impl FnOnce(&CodegenCx<'ll, 'tcx>, &str) -> &'ll DIType,
177 ) -> StubInfo<'ll, 'tcx> {
178 let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx);
179 let di_node = build(cx, &unique_type_id_str);
180 StubInfo { metadata: di_node, unique_type_id }
181 }
182}
183
184pub(super) fn stub<'ll, 'tcx>(
186 cx: &CodegenCx<'ll, 'tcx>,
187 kind: Stub<'ll>,
188 unique_type_id: UniqueTypeId<'tcx>,
189 name: &str,
190 def_location: Option<DefinitionLocation<'ll>>,
191 (size, align): (Size, Align),
192 containing_scope: Option<&'ll DIScope>,
193 flags: DIFlags,
194) -> StubInfo<'ll, 'tcx> {
195 let no_elements: &[Option<&llvm::Metadata>] = &[];
196 let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx);
197
198 let (file_metadata, line_number) = if let Some(def_location) = def_location {
199 (def_location.0, def_location.1)
200 } else {
201 (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
202 };
203
204 let metadata = match kind {
205 Stub::Struct | Stub::VTableTy { .. } => {
206 let vtable_holder = match kind {
207 Stub::VTableTy { vtable_holder } => Some(vtable_holder),
208 _ => None,
209 };
210 unsafe {
211 llvm::LLVMDIBuilderCreateStructType(
212 DIB(cx),
213 containing_scope,
214 name.as_ptr(),
215 name.len(),
216 file_metadata,
217 line_number,
218 size.bits(),
219 align.bits() as u32,
220 flags,
221 None,
222 no_elements.as_ptr(),
223 no_elements.len() as c_uint,
224 0u32, vtable_holder,
226 unique_type_id_str.as_ptr(),
227 unique_type_id_str.len(),
228 )
229 }
230 }
231 Stub::Union => unsafe {
232 llvm::LLVMDIBuilderCreateUnionType(
233 DIB(cx),
234 containing_scope,
235 name.as_ptr(),
236 name.len(),
237 file_metadata,
238 line_number,
239 size.bits(),
240 align.bits() as u32,
241 flags,
242 no_elements.as_ptr(),
243 no_elements.len() as c_uint,
244 0u32, unique_type_id_str.as_ptr(),
246 unique_type_id_str.len(),
247 )
248 },
249 };
250 StubInfo { metadata, unique_type_id }
251}
252
253struct AdtStackPopGuard<'ll, 'tcx, 'a> {
254 cx: &'a CodegenCx<'ll, 'tcx>,
255}
256
257impl<'ll, 'tcx, 'a> Drop for AdtStackPopGuard<'ll, 'tcx, 'a> {
258 fn drop(&mut self) {
259 debug_context(self.cx).adt_stack.borrow_mut().pop();
260 }
261}
262
263pub(super) fn build_type_with_children<'ll, 'tcx>(
270 cx: &CodegenCx<'ll, 'tcx>,
271 stub_info: StubInfo<'ll, 'tcx>,
272 members: impl FnOnce(&CodegenCx<'ll, 'tcx>, &'ll DIType) -> SmallVec<&'ll DIType>,
273 generics: impl FnOnce(&CodegenCx<'ll, 'tcx>) -> SmallVec<Option<&'ll DIType>>,
274) -> DINodeCreationResult<'ll> {
275 assert_eq!(debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None);
276
277 let mut _adt_stack_pop_guard = None;
278 if let UniqueTypeId::Ty(ty, ..) = stub_info.unique_type_id
279 && let ty::Adt(adt_def, args) = ty.kind()
280 {
281 let def_id = adt_def.did();
282 let is_expanding_recursive = {
292 let stack = debug_context(cx).adt_stack.borrow();
293 stack
294 .iter()
295 .enumerate()
296 .rev()
297 .skip(1)
298 .filter(|(_, (ancestor_def_id, _))| def_id == *ancestor_def_id)
299 .any(|(ancestor_index, (_, ancestor_args))| {
300 args.iter()
301 .zip(ancestor_args.iter())
302 .filter_map(|(arg, ancestor_arg)| arg.as_type().zip(ancestor_arg.as_type()))
303 .any(|(arg, ancestor_arg)|
304 (arg != ancestor_arg && arg.contains(ancestor_arg))
306 && stack[ancestor_index + 1..stack.len()].iter().all(
320 |(_, intermediate_args)|
321 intermediate_args
322 .iter()
323 .filter_map(|arg| arg.as_type())
324 .any(|mid_arg| mid_arg.contains(ancestor_arg))
325 ))
326 })
327 };
328 if is_expanding_recursive {
329 return DINodeCreationResult::new(stub_info.metadata, false);
331 } else {
332 debug_context(cx).adt_stack.borrow_mut().push((def_id, args));
333 _adt_stack_pop_guard = Some(AdtStackPopGuard { cx });
334 }
335 }
336
337 debug_context(cx).type_map.insert(stub_info.unique_type_id, stub_info.metadata);
338
339 let members: SmallVec<_> =
340 members(cx, stub_info.metadata).into_iter().map(|node| Some(node)).collect();
341 let generics = generics(cx);
342
343 if !(members.is_empty() && generics.is_empty()) {
344 unsafe {
345 let members_array = create_DIArray(DIB(cx), &members[..]);
346 let generics_array = create_DIArray(DIB(cx), &generics[..]);
347 llvm::LLVMRustDICompositeTypeReplaceArrays(
348 DIB(cx),
349 stub_info.metadata,
350 Some(members_array),
351 Some(generics_array),
352 );
353 }
354 }
355
356 DINodeCreationResult { di_node: stub_info.metadata, already_stored_in_typemap: true }
357}