]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / compiler / rustc_codegen_llvm / src / debuginfo / metadata / enums / mod.rs
CommitLineData
5e7ed085
FG
1use rustc_codegen_ssa::debuginfo::{
2 type_names::{compute_debuginfo_type_name, cpp_like_debuginfo},
3 wants_c_like_enum_debuginfo,
4};
5use rustc_hir::def::CtorKind;
49aad941 6use rustc_index::IndexSlice;
5e7ed085
FG
7use rustc_middle::{
8 bug,
ed00b5ec 9 mir::CoroutineLayout,
5e7ed085
FG
10 ty::{
11 self,
12 layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout},
ed00b5ec 13 AdtDef, CoroutineArgs, Ty, VariantDef,
5e7ed085
FG
14 },
15};
16use rustc_span::Symbol;
353b0b11
FG
17use rustc_target::abi::{
18 FieldIdx, HasDataLayout, Integer, Primitive, TagEncoding, VariantIdx, Variants,
19};
5e7ed085
FG
20use std::borrow::Cow;
21
22use crate::{
23 common::CodegenCx,
24 debuginfo::{
25 metadata::{
26 build_field_di_node, build_generic_type_param_di_nodes, type_di_node,
27 type_map::{self, Stub},
28 unknown_file_metadata, UNKNOWN_LINE_NUMBER,
29 },
30 utils::{create_DIArray, get_namespace_for_item, DIB},
31 },
32 llvm::{
33 self,
34 debuginfo::{DIFlags, DIType},
35 },
36};
37
38use super::{
39 size_and_align_of,
40 type_map::{DINodeCreationResult, UniqueTypeId},
41 SmallVec,
42};
43
44mod cpp_like;
45mod native;
46
47pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
48 cx: &CodegenCx<'ll, 'tcx>,
49 unique_type_id: UniqueTypeId<'tcx>,
50) -> DINodeCreationResult<'ll> {
51 let enum_type = unique_type_id.expect_ty();
52 let &ty::Adt(enum_adt_def, _) = enum_type.kind() else {
53 bug!("build_enum_type_di_node() called with non-enum type: `{:?}`", enum_type)
add651ee 54 };
5e7ed085
FG
55
56 let enum_type_and_layout = cx.layout_of(enum_type);
57
58 if wants_c_like_enum_debuginfo(enum_type_and_layout) {
59 return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout);
60 }
61
62 if cpp_like_debuginfo(cx.tcx) {
63 cpp_like::build_enum_type_di_node(cx, unique_type_id)
64 } else {
65 native::build_enum_type_di_node(cx, unique_type_id)
66 }
67}
68
ed00b5ec 69pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
5e7ed085
FG
70 cx: &CodegenCx<'ll, 'tcx>,
71 unique_type_id: UniqueTypeId<'tcx>,
72) -> DINodeCreationResult<'ll> {
73 if cpp_like_debuginfo(cx.tcx) {
ed00b5ec 74 cpp_like::build_coroutine_di_node(cx, unique_type_id)
5e7ed085 75 } else {
ed00b5ec 76 native::build_coroutine_di_node(cx, unique_type_id)
5e7ed085
FG
77 }
78}
79
80/// Build the debuginfo node for a C-style enum, i.e. an enum the variants of which have no fields.
81///
82/// The resulting debuginfo will be a DW_TAG_enumeration_type.
83fn build_c_style_enum_di_node<'ll, 'tcx>(
84 cx: &CodegenCx<'ll, 'tcx>,
85 enum_adt_def: AdtDef<'tcx>,
86 enum_type_and_layout: TyAndLayout<'tcx>,
87) -> DINodeCreationResult<'ll> {
88 let containing_scope = get_namespace_for_item(cx, enum_adt_def.did());
89 DINodeCreationResult {
90 di_node: build_enumeration_type_di_node(
91 cx,
92 &compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
93 tag_base_type(cx, enum_type_and_layout),
f2b60f7d
FG
94 enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
95 let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
487cf647 96 (name, discr.val)
5e7ed085
FG
97 }),
98 containing_scope,
99 ),
100 already_stored_in_typemap: false,
101 }
102}
103
ed00b5ec 104/// Extract the type with which we want to describe the tag of the given enum or coroutine.
5e7ed085
FG
105fn tag_base_type<'ll, 'tcx>(
106 cx: &CodegenCx<'ll, 'tcx>,
107 enum_type_and_layout: TyAndLayout<'tcx>,
108) -> Ty<'tcx> {
109 debug_assert!(match enum_type_and_layout.ty.kind() {
ed00b5ec 110 ty::Coroutine(..) => true,
5e7ed085
FG
111 ty::Adt(adt_def, _) => adt_def.is_enum(),
112 _ => false,
113 });
114
115 match enum_type_and_layout.layout.variants() {
116 // A single-variant enum has no discriminant.
117 Variants::Single { .. } => {
118 bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
119 }
120
121 Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
122 // Niche tags are always normalized to unsized integers of the correct size.
04454e1e 123 match tag.primitive() {
5e7ed085
FG
124 Primitive::Int(t, _) => t,
125 Primitive::F32 => Integer::I32,
126 Primitive::F64 => Integer::I64,
9ffffee4
FG
127 // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
128 Primitive::Pointer(_) => {
5e7ed085
FG
129 // If the niche is the NULL value of a reference, then `discr_enum_ty` will be
130 // a RawPtr. CodeView doesn't know what to do with enums whose base type is a
131 // pointer so we fix this up to just be `usize`.
132 // DWARF might be able to deal with this but with an integer type we are on
133 // the safe side there too.
134 cx.data_layout().ptr_sized_integer()
135 }
136 }
137 .to_ty(cx.tcx, false)
138 }
139
140 Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
141 // Direct tags preserve the sign.
04454e1e 142 tag.primitive().to_ty(cx.tcx)
5e7ed085
FG
143 }
144 }
145}
146
147/// Build a DW_TAG_enumeration_type debuginfo node, with the given base type and variants.
148/// This is a helper function and does not register anything in the type map by itself.
149///
150/// `variants` is an iterator of (discr-value, variant-name).
5e7ed085
FG
151fn build_enumeration_type_di_node<'ll, 'tcx>(
152 cx: &CodegenCx<'ll, 'tcx>,
153 type_name: &str,
154 base_type: Ty<'tcx>,
487cf647 155 enumerators: impl Iterator<Item = (Cow<'tcx, str>, u128)>,
5e7ed085
FG
156 containing_scope: &'ll DIType,
157) -> &'ll DIType {
158 let is_unsigned = match base_type.kind() {
159 ty::Int(_) => false,
160 ty::Uint(_) => true,
161 _ => bug!("build_enumeration_type_di_node() called with non-integer tag type."),
162 };
487cf647 163 let (size, align) = cx.size_and_align_of(base_type);
5e7ed085 164
f2b60f7d
FG
165 let enumerator_di_nodes: SmallVec<Option<&'ll DIType>> = enumerators
166 .map(|(name, value)| unsafe {
487cf647 167 let value = [value as u64, (value >> 64) as u64];
f2b60f7d
FG
168 Some(llvm::LLVMRustDIBuilderCreateEnumerator(
169 DIB(cx),
170 name.as_ptr().cast(),
171 name.len(),
487cf647
FG
172 value.as_ptr(),
173 size.bits() as libc::c_uint,
f2b60f7d
FG
174 is_unsigned,
175 ))
5e7ed085
FG
176 })
177 .collect();
178
5e7ed085
FG
179 unsafe {
180 llvm::LLVMRustDIBuilderCreateEnumerationType(
181 DIB(cx),
182 containing_scope,
183 type_name.as_ptr().cast(),
184 type_name.len(),
185 unknown_file_metadata(cx),
186 UNKNOWN_LINE_NUMBER,
187 size.bits(),
188 align.bits() as u32,
189 create_DIArray(DIB(cx), &enumerator_di_nodes[..]),
190 type_di_node(cx, base_type),
191 true,
192 )
193 }
194}
195
196/// Build the debuginfo node for the struct type describing a single variant of an enum.
197///
198/// ```txt
199/// DW_TAG_structure_type (top-level type for enum)
200/// DW_TAG_variant_part (variant part)
201/// DW_AT_discr (reference to discriminant DW_TAG_member)
202/// DW_TAG_member (discriminant member)
203/// DW_TAG_variant (variant 1)
204/// DW_TAG_variant (variant 2)
205/// DW_TAG_variant (variant 3)
206/// ---> DW_TAG_structure_type (type of variant 1)
207/// ---> DW_TAG_structure_type (type of variant 2)
208/// ---> DW_TAG_structure_type (type of variant 3)
209/// ```
210///
211/// In CPP-like mode, we have the exact same descriptions for each variant too:
212///
213/// ```txt
214/// DW_TAG_union_type (top-level type for enum)
215/// DW_TAG_member (member for variant 1)
216/// DW_TAG_member (member for variant 2)
217/// DW_TAG_member (member for variant 3)
218/// ---> DW_TAG_structure_type (type of variant 1)
219/// ---> DW_TAG_structure_type (type of variant 2)
220/// ---> DW_TAG_structure_type (type of variant 3)
221/// DW_TAG_enumeration_type (type of tag)
222/// ```
223///
224/// The node looks like:
225///
226/// ```txt
227/// DW_TAG_structure_type
228/// DW_AT_name <name-of-variant>
229/// DW_AT_byte_size 0x00000010
230/// DW_AT_alignment 0x00000008
231/// DW_TAG_member
232/// DW_AT_name <name-of-field-0>
233/// DW_AT_type <0x0000018e>
234/// DW_AT_alignment 0x00000004
235/// DW_AT_data_member_location 4
236/// DW_TAG_member
237/// DW_AT_name <name-of-field-1>
238/// DW_AT_type <0x00000195>
239/// DW_AT_alignment 0x00000008
240/// DW_AT_data_member_location 8
241/// ...
242/// ```
243///
244/// The type of a variant is always a struct type with the name of the variant
245/// and a DW_TAG_member for each field (but not the discriminant).
246fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
247 cx: &CodegenCx<'ll, 'tcx>,
f2b60f7d 248 enum_type_and_layout: TyAndLayout<'tcx>,
5e7ed085
FG
249 enum_type_di_node: &'ll DIType,
250 variant_index: VariantIdx,
251 variant_def: &VariantDef,
252 variant_layout: TyAndLayout<'tcx>,
4b012472 253 di_flags: DIFlags,
5e7ed085 254) -> &'ll DIType {
f2b60f7d 255 debug_assert_eq!(variant_layout.ty, enum_type_and_layout.ty);
5e7ed085
FG
256
257 type_map::build_type_with_children(
258 cx,
259 type_map::stub(
260 cx,
261 Stub::Struct,
f2b60f7d
FG
262 UniqueTypeId::for_enum_variant_struct_type(
263 cx.tcx,
264 enum_type_and_layout.ty,
265 variant_index,
266 ),
5e7ed085
FG
267 variant_def.name.as_str(),
268 // NOTE: We use size and align of enum_type, not from variant_layout:
f2b60f7d 269 size_and_align_of(enum_type_and_layout),
5e7ed085 270 Some(enum_type_di_node),
4b012472 271 di_flags,
5e7ed085
FG
272 ),
273 |cx, struct_type_di_node| {
274 (0..variant_layout.fields.count())
275 .map(|field_index| {
487cf647 276 let field_name = if variant_def.ctor_kind() != Some(CtorKind::Fn) {
5e7ed085 277 // Fields have names
353b0b11
FG
278 let field = &variant_def.fields[FieldIdx::from_usize(field_index)];
279 Cow::from(field.name.as_str())
5e7ed085
FG
280 } else {
281 // Tuple-like
282 super::tuple_field_name(field_index)
283 };
284
285 let field_layout = variant_layout.field(cx, field_index);
286
287 build_field_di_node(
288 cx,
289 struct_type_di_node,
290 &field_name,
291 (field_layout.size, field_layout.align.abi),
292 variant_layout.fields.offset(field_index),
4b012472 293 di_flags,
5e7ed085
FG
294 type_di_node(cx, field_layout.ty),
295 )
296 })
f2b60f7d 297 .collect::<SmallVec<_>>()
5e7ed085 298 },
f2b60f7d 299 |cx| build_generic_type_param_di_nodes(cx, enum_type_and_layout.ty),
5e7ed085
FG
300 )
301 .di_node
302}
303
ed00b5ec
FG
304/// Build the struct type for describing a single coroutine state.
305/// See [build_coroutine_variant_struct_type_di_node].
5e7ed085
FG
306///
307/// ```txt
308///
309/// DW_TAG_structure_type (top-level type for enum)
310/// DW_TAG_variant_part (variant part)
311/// DW_AT_discr (reference to discriminant DW_TAG_member)
312/// DW_TAG_member (discriminant member)
313/// DW_TAG_variant (variant 1)
314/// DW_TAG_variant (variant 2)
315/// DW_TAG_variant (variant 3)
316/// ---> DW_TAG_structure_type (type of variant 1)
317/// ---> DW_TAG_structure_type (type of variant 2)
318/// ---> DW_TAG_structure_type (type of variant 3)
319///
320/// ```
ed00b5ec 321pub fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
5e7ed085
FG
322 cx: &CodegenCx<'ll, 'tcx>,
323 variant_index: VariantIdx,
ed00b5ec
FG
324 coroutine_type_and_layout: TyAndLayout<'tcx>,
325 coroutine_type_di_node: &'ll DIType,
326 coroutine_layout: &CoroutineLayout<'tcx>,
fe692bf9 327 common_upvar_names: &IndexSlice<FieldIdx, Symbol>,
5e7ed085 328) -> &'ll DIType {
ed00b5ec 329 let variant_name = CoroutineArgs::variant_name(variant_index);
5e7ed085
FG
330 let unique_type_id = UniqueTypeId::for_enum_variant_struct_type(
331 cx.tcx,
ed00b5ec 332 coroutine_type_and_layout.ty,
5e7ed085
FG
333 variant_index,
334 );
335
ed00b5ec 336 let variant_layout = coroutine_type_and_layout.for_variant(cx, variant_index);
5e7ed085 337
ed00b5ec
FG
338 let coroutine_args = match coroutine_type_and_layout.ty.kind() {
339 ty::Coroutine(_, args, _) => args.as_coroutine(),
5e7ed085
FG
340 _ => unreachable!(),
341 };
342
343 type_map::build_type_with_children(
344 cx,
345 type_map::stub(
346 cx,
347 Stub::Struct,
348 unique_type_id,
349 &variant_name,
ed00b5ec
FG
350 size_and_align_of(coroutine_type_and_layout),
351 Some(coroutine_type_di_node),
5e7ed085
FG
352 DIFlags::FlagZero,
353 ),
354 |cx, variant_struct_type_di_node| {
355 // Fields that just belong to this variant/state
356 let state_specific_fields: SmallVec<_> = (0..variant_layout.fields.count())
357 .map(|field_index| {
ed00b5ec 358 let coroutine_saved_local = coroutine_layout.variant_fields[variant_index]
353b0b11 359 [FieldIdx::from_usize(field_index)];
ed00b5ec 360 let field_name_maybe = coroutine_layout.field_names[coroutine_saved_local];
5e7ed085
FG
361 let field_name = field_name_maybe
362 .as_ref()
363 .map(|s| Cow::from(s.as_str()))
364 .unwrap_or_else(|| super::tuple_field_name(field_index));
365
366 let field_type = variant_layout.field(cx, field_index).ty;
367
368 build_field_di_node(
369 cx,
370 variant_struct_type_di_node,
371 &field_name,
372 cx.size_and_align_of(field_type),
373 variant_layout.fields.offset(field_index),
374 DIFlags::FlagZero,
375 type_di_node(cx, field_type),
376 )
377 })
378 .collect();
379
380 // Fields that are common to all states
ed00b5ec 381 let common_fields: SmallVec<_> = coroutine_args
5e7ed085 382 .prefix_tys()
add651ee 383 .iter()
fe692bf9 384 .zip(common_upvar_names)
5e7ed085 385 .enumerate()
fe692bf9 386 .map(|(index, (upvar_ty, upvar_name))| {
5e7ed085
FG
387 build_field_di_node(
388 cx,
389 variant_struct_type_di_node,
fe692bf9 390 upvar_name.as_str(),
5e7ed085 391 cx.size_and_align_of(upvar_ty),
ed00b5ec 392 coroutine_type_and_layout.fields.offset(index),
5e7ed085
FG
393 DIFlags::FlagZero,
394 type_di_node(cx, upvar_ty),
395 )
396 })
397 .collect();
398
4b012472 399 state_specific_fields.into_iter().chain(common_fields).collect()
5e7ed085 400 },
ed00b5ec 401 |cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
5e7ed085
FG
402 )
403 .di_node
404}
405
f2b60f7d
FG
406#[derive(Copy, Clone)]
407enum DiscrResult {
408 NoDiscriminant,
409 Value(u128),
410 Range(u128, u128),
411}
412
413impl DiscrResult {
414 fn opt_single_val(&self) -> Option<u128> {
415 if let Self::Value(d) = *self { Some(d) } else { None }
416 }
417}
418
5e7ed085
FG
419/// Returns the discriminant value corresponding to the variant index.
420///
421/// Will return `None` if there is less than two variants (because then the enum won't have)
f2b60f7d 422/// a tag, and if this is the untagged variant of a niche-layout enum (because then there is no
5e7ed085
FG
423/// single discriminant value).
424fn compute_discriminant_value<'ll, 'tcx>(
425 cx: &CodegenCx<'ll, 'tcx>,
426 enum_type_and_layout: TyAndLayout<'tcx>,
427 variant_index: VariantIdx,
f2b60f7d 428) -> DiscrResult {
5e7ed085 429 match enum_type_and_layout.layout.variants() {
f2b60f7d
FG
430 &Variants::Single { .. } => DiscrResult::NoDiscriminant,
431 &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value(
432 enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
5e7ed085
FG
433 ),
434 &Variants::Multiple {
f2b60f7d 435 tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, untagged_variant },
5e7ed085
FG
436 tag,
437 ..
438 } => {
f2b60f7d
FG
439 if variant_index == untagged_variant {
440 let valid_range = enum_type_and_layout
441 .for_variant(cx, variant_index)
442 .largest_niche
443 .as_ref()
444 .unwrap()
445 .valid_range;
446
447 let min = valid_range.start.min(valid_range.end);
448 let min = tag.size(cx).truncate(min);
449
450 let max = valid_range.start.max(valid_range.end);
451 let max = tag.size(cx).truncate(max);
452
453 DiscrResult::Range(min, max)
5e7ed085
FG
454 } else {
455 let value = (variant_index.as_u32() as u128)
456 .wrapping_sub(niche_variants.start().as_u32() as u128)
457 .wrapping_add(niche_start);
04454e1e 458 let value = tag.size(cx).truncate(value);
f2b60f7d 459 DiscrResult::Value(value)
5e7ed085
FG
460 }
461 }
462 }
463}