rustc_codegen_llvm/debuginfo/metadata/enums/
mod.rs1use std::borrow::Cow;
2
3use rustc_abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
4use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_like_debuginfo};
5use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
6use rustc_codegen_ssa::traits::MiscCodegenMethods;
7use rustc_hir::def::CtorKind;
8use rustc_index::IndexSlice;
9use rustc_middle::mir::CoroutineLayout;
10use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
11use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef};
12use rustc_span::{Span, Symbol, bug};
13
14use super::type_map::{DINodeCreationResult, UniqueTypeId};
15use super::{SmallVec, size_and_align_of};
16use crate::common::{AsCCharPtr, CodegenCx};
17use crate::debuginfo::metadata::type_map::{self, Stub};
18use crate::debuginfo::metadata::{
19 UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes,
20 file_metadata_from_def_id, type_di_node, unknown_file_metadata,
21};
22use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
23use crate::llvm::debuginfo::{DIFlags, DIType};
24use crate::llvm::{self, ToLlvmBool};
25
26mod cpp_like;
27mod native;
28
29pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
30 cx: &CodegenCx<'ll, 'tcx>,
31 unique_type_id: UniqueTypeId<'tcx>,
32 span: Span,
33) -> DINodeCreationResult<'ll> {
34 let enum_type = unique_type_id.expect_ty();
35 let &ty::Adt(enum_adt_def, _) = enum_type.kind() else {
36 bug_impl(None,
format_args!("build_enum_type_di_node() called with non-enum type: `{0:?}`",
enum_type), Location::caller())bug!("build_enum_type_di_node() called with non-enum type: `{:?}`", enum_type)
37 };
38
39 let enum_type_and_layout = cx.spanned_layout_of(enum_type, span);
40
41 if wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout) {
42 return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout);
43 }
44
45 if cpp_like_debuginfo(cx.tcx) {
46 cpp_like::build_enum_type_di_node(cx, unique_type_id)
47 } else {
48 native::build_enum_type_di_node(cx, unique_type_id)
49 }
50}
51
52pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
53 cx: &CodegenCx<'ll, 'tcx>,
54 unique_type_id: UniqueTypeId<'tcx>,
55) -> DINodeCreationResult<'ll> {
56 if cpp_like_debuginfo(cx.tcx) {
57 cpp_like::build_coroutine_di_node(cx, unique_type_id)
58 } else {
59 native::build_coroutine_di_node(cx, unique_type_id)
60 }
61}
62
63fn build_c_style_enum_di_node<'ll, 'tcx>(
67 cx: &CodegenCx<'ll, 'tcx>,
68 enum_adt_def: AdtDef<'tcx>,
69 enum_type_and_layout: TyAndLayout<'tcx>,
70) -> DINodeCreationResult<'ll> {
71 let containing_scope = get_namespace_for_item(cx, enum_adt_def.did());
72 let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
73 Some(enum_adt_def.did())
74 } else {
75 None
76 };
77 DINodeCreationResult {
78 di_node: build_enumeration_type_di_node(
79 cx,
80 &compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
81 tag_base_type(cx.tcx, enum_type_and_layout),
82 enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
83 let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
84 (name, discr.val)
85 }),
86 enum_adt_def_id,
87 containing_scope,
88 ),
89 already_stored_in_typemap: false,
90 }
91}
92
93fn build_enumeration_type_di_node<'ll, 'tcx>(
98 cx: &CodegenCx<'ll, 'tcx>,
99 type_name: &str,
100 base_type: Ty<'tcx>,
101 enumerators: impl Iterator<Item = (Cow<'tcx, str>, u128)>,
102 def_id: Option<rustc_span::def_id::DefId>,
103 containing_scope: &'ll DIType,
104) -> &'ll DIType {
105 let is_unsigned = match base_type.kind() {
106 ty::Int(_) => false,
107 ty::Uint(_) => true,
108 _ => bug_impl(None,
format_args!("build_enumeration_type_di_node() called with non-integer tag type."),
Location::caller())bug!("build_enumeration_type_di_node() called with non-integer tag type."),
109 };
110 let (size, align) = cx.size_and_align_of(base_type);
111
112 let enumerator_di_nodes: SmallVec<Option<&'ll DIType>> = enumerators
113 .map(|(name, value)| {
114 let value_words = [value as u64, (value >> 64) as u64];
115 let size_in_bits = size.bits();
116 if !((size_in_bits + 63) / 64 <= value_words.len() as u64) {
::core::panicking::panic("assertion failed: (size_in_bits + 63) / 64 <= value_words.len() as u64")
};assert!((size_in_bits + 63) / 64 <= value_words.len() as u64);
118
119 let enumerator = unsafe {
120 llvm::LLVMDIBuilderCreateEnumeratorOfArbitraryPrecision(
121 DIB(cx),
122 name.as_ptr(),
123 name.len(),
124 size_in_bits,
125 value_words.as_ptr(),
126 is_unsigned.to_llvm_bool(),
127 )
128 };
129 Some(enumerator)
130 })
131 .collect();
132
133 let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
134 {
135 file_metadata_from_def_id(cx, def_id)
136 } else {
137 (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
138 };
139
140 unsafe {
141 llvm::LLVMRustDIBuilderCreateEnumerationType(
142 DIB(cx),
143 containing_scope,
144 type_name.as_c_char_ptr(),
145 type_name.len(),
146 file_metadata,
147 line_number,
148 size.bits(),
149 align.bits() as u32,
150 create_DIArray(DIB(cx), &enumerator_di_nodes[..]),
151 type_di_node(cx, base_type),
152 true,
153 )
154 }
155}
156
157fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
208 cx: &CodegenCx<'ll, 'tcx>,
209 enum_type_and_layout: TyAndLayout<'tcx>,
210 enum_type_di_node: &'ll DIType,
211 variant_index: VariantIdx,
212 variant_def: &VariantDef,
213 variant_layout: TyAndLayout<'tcx>,
214 di_flags: DIFlags,
215) -> &'ll DIType {
216 {
match (&variant_layout.ty, &enum_type_and_layout.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(variant_layout.ty, enum_type_and_layout.ty);
217
218 let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
219 Some(file_metadata_from_def_id(cx, Some(variant_def.def_id)))
220 } else {
221 None
222 };
223
224 type_map::build_type_with_children(
225 cx,
226 type_map::stub(
227 cx,
228 Stub::Struct,
229 UniqueTypeId::for_enum_variant_struct_type(
230 cx.tcx,
231 enum_type_and_layout.ty,
232 variant_index,
233 ),
234 variant_def.name.as_str(),
235 def_location,
236 size_and_align_of(enum_type_and_layout),
238 Some(enum_type_di_node),
239 di_flags,
240 ),
241 |cx, struct_type_di_node| {
242 (0..variant_layout.fields.count())
243 .map(|field_index| {
244 let field_name = if variant_def.ctor_kind() != Some(CtorKind::Fn) {
245 let field = &variant_def.fields[FieldIdx::from_usize(field_index)];
247 Cow::from(field.name.as_str())
248 } else {
249 super::tuple_field_name(field_index)
251 };
252
253 let field_layout = variant_layout.field(cx, field_index);
254
255 build_field_di_node(
256 cx,
257 struct_type_di_node,
258 &field_name,
259 field_layout,
260 variant_layout.fields.offset(field_index),
261 di_flags,
262 type_di_node(cx, field_layout.ty),
263 None,
264 )
265 })
266 .collect::<SmallVec<_>>()
267 },
268 |cx| build_generic_type_param_di_nodes(cx, enum_type_and_layout.ty),
269 )
270 .di_node
271}
272
273fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
291 cx: &CodegenCx<'ll, 'tcx>,
292 variant_index: VariantIdx,
293 coroutine_type_and_layout: TyAndLayout<'tcx>,
294 coroutine_type_di_node: &'ll DIType,
295 coroutine_layout: &CoroutineLayout<'tcx>,
296 common_upvar_names: &IndexSlice<FieldIdx, Symbol>,
297) -> &'ll DIType {
298 let variant_name = CoroutineArgs::variant_name(variant_index);
299 let unique_type_id = UniqueTypeId::for_enum_variant_struct_type(
300 cx.tcx,
301 coroutine_type_and_layout.ty,
302 variant_index,
303 );
304
305 let variant_layout = coroutine_type_and_layout.for_variant(cx, variant_index);
306
307 let coroutine_args = match coroutine_type_and_layout.ty.kind() {
308 ty::Coroutine(_, args) => args.as_coroutine(),
309 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
310 };
311
312 type_map::build_type_with_children(
313 cx,
314 type_map::stub(
315 cx,
316 Stub::Struct,
317 unique_type_id,
318 &variant_name,
319 None,
320 size_and_align_of(coroutine_type_and_layout),
321 Some(coroutine_type_di_node),
322 DIFlags::FlagZero,
323 ),
324 |cx, variant_struct_type_di_node| {
325 let state_specific_fields: SmallVec<_> = (0..variant_layout.fields.count())
327 .map(|field_index| {
328 let coroutine_saved_local = coroutine_layout.variant_fields[variant_index]
329 [FieldIdx::from_usize(field_index)];
330 let field_name_maybe =
331 coroutine_layout.field_tys[coroutine_saved_local].debuginfo_name;
332 let field_name = field_name_maybe
333 .as_ref()
334 .map(|s| Cow::from(s.as_str()))
335 .unwrap_or_else(|| super::tuple_field_name(field_index));
336
337 let field_type = variant_layout.field(cx, field_index).ty;
338
339 build_field_di_node(
340 cx,
341 variant_struct_type_di_node,
342 &field_name,
343 cx.layout_of(field_type),
344 variant_layout.fields.offset(field_index),
345 DIFlags::FlagZero,
346 type_di_node(cx, field_type),
347 None,
348 )
349 })
350 .collect();
351
352 let common_fields: SmallVec<_> = coroutine_args
354 .upvar_tys()
355 .iter()
356 .zip(common_upvar_names)
357 .enumerate()
358 .map(|(index, (upvar_ty, upvar_name))| {
359 build_field_di_node(
360 cx,
361 variant_struct_type_di_node,
362 upvar_name.as_str(),
363 cx.layout_of(upvar_ty),
364 coroutine_type_and_layout.fields.offset(index),
365 DIFlags::FlagZero,
366 type_di_node(cx, upvar_ty),
367 None,
368 )
369 })
370 .collect();
371
372 state_specific_fields.into_iter().chain(common_fields).collect()
373 },
374 |cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
375 )
376 .di_node
377}
378
379#[derive(#[automatically_derived]
impl ::core::marker::Copy for DiscrResult { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for DiscrResult { }
#[automatically_derived]
impl ::core::clone::Clone for DiscrResult {
#[inline]
fn clone(&self) -> DiscrResult {
let _: ::core::clone::AssertParamIsClone<u128>;
*self
}
}Clone)]
380enum DiscrResult {
381 NoDiscriminant,
382 Value(u128),
383 Range(u128, u128),
384}
385
386impl DiscrResult {
387 fn opt_single_val(&self) -> Option<u128> {
388 if let Self::Value(d) = *self { Some(d) } else { None }
389 }
390}
391
392fn compute_discriminant_value<'ll, 'tcx>(
398 cx: &CodegenCx<'ll, 'tcx>,
399 enum_type_and_layout: TyAndLayout<'tcx>,
400 variant_index: VariantIdx,
401) -> DiscrResult {
402 match enum_type_and_layout.layout.variants() {
403 &Variants::Single { .. } | &Variants::Empty => DiscrResult::NoDiscriminant,
404 &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value(
405 enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
406 ),
407 &Variants::Multiple {
408 tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, untagged_variant },
409 tag,
410 ..
411 } => {
412 if variant_index == untagged_variant {
413 let valid_range = enum_type_and_layout
414 .for_variant(cx, variant_index)
415 .largest_niche
416 .as_ref()
417 .unwrap()
418 .valid_range;
419
420 let min = valid_range.start.min(valid_range.end);
421 let min = tag.size(cx).truncate(min);
422
423 let max = valid_range.start.max(valid_range.end);
424 let max = tag.size(cx).truncate(max);
425
426 DiscrResult::Range(min, max)
427 } else {
428 let value = (variant_index.as_u32() as u128)
429 .wrapping_sub(niche_variants.start.as_u32() as u128)
430 .wrapping_add(niche_start);
431 let value = tag.size(cx).truncate(value);
432 DiscrResult::Value(value)
433 }
434 }
435 }
436}