rustc_codegen_llvm/debuginfo/metadata/
type_map.rs1use 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 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)]
25 pub(crate) struct HiddenZst;
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, HashStable)]
36pub(super) enum UniqueTypeId<'tcx> {
37 Ty(Ty<'tcx>, private::HiddenZst),
39 VariantPart(Ty<'tcx>, private::HiddenZst),
42 VariantStructType(Ty<'tcx>, VariantIdx, private::HiddenZst),
44 VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst),
46 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 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#[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 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>, &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
183pub(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
250pub(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}