rustc_codegen_llvm/debuginfo/metadata/enums/native.rs
1use std::borrow::Cow;
2
3use libc::c_uint;
4use rustc_abi::{Size, TagEncoding, VariantIdx, Variants};
5use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
6use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
7use rustc_codegen_ssa::traits::{ConstCodegenMethods, MiscCodegenMethods};
8use rustc_middle::bug;
9use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
10use rustc_middle::ty::{self};
11use smallvec::smallvec;
12
13use crate::common::{AsCCharPtr, CodegenCx};
14use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
15use crate::debuginfo::metadata::{
16 DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, file_metadata,
17 file_metadata_from_def_id, size_and_align_of, type_di_node, unknown_file_metadata,
18 visibility_di_flags,
19};
20use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
21use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
22use crate::llvm::{self};
23
24/// Build the debuginfo node for an enum type. The listing below shows how such a
25/// type looks like at the LLVM IR/DWARF level. It is a `DW_TAG_structure_type`
26/// with a single `DW_TAG_variant_part` that in turn contains a `DW_TAG_variant`
27/// for each variant of the enum. The variant-part also contains a single member
28/// describing the discriminant, and a nested struct type for each of the variants.
29///
30/// ```txt
31/// ---> DW_TAG_structure_type (top-level type for enum)
32/// DW_TAG_variant_part (variant part)
33/// DW_AT_discr (reference to discriminant DW_TAG_member)
34/// DW_TAG_member (discriminant member)
35/// DW_TAG_variant (variant 1)
36/// DW_TAG_variant (variant 2)
37/// DW_TAG_variant (variant 3)
38/// DW_TAG_structure_type (type of variant 1)
39/// DW_TAG_structure_type (type of variant 2)
40/// DW_TAG_structure_type (type of variant 3)
41/// ```
42pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
43 cx: &CodegenCx<'ll, 'tcx>,
44 unique_type_id: UniqueTypeId<'tcx>,
45) -> DINodeCreationResult<'ll> {
46 let enum_type = unique_type_id.expect_ty();
47 let &ty::Adt(enum_adt_def, _) = enum_type.kind() else {
48 bug!("build_enum_type_di_node() called with non-enum type: `{:?}`", enum_type)
49 };
50
51 let containing_scope = get_namespace_for_item(cx, enum_adt_def.did());
52 let enum_type_and_layout = cx.layout_of(enum_type);
53 let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
54
55 let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
56
57 assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
58
59 let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
60 Some(file_metadata_from_def_id(cx, Some(enum_adt_def.did())))
61 } else {
62 None
63 };
64
65 type_map::build_type_with_children(
66 cx,
67 type_map::stub(
68 cx,
69 Stub::Struct,
70 unique_type_id,
71 &enum_type_name,
72 def_location,
73 size_and_align_of(enum_type_and_layout),
74 Some(containing_scope),
75 visibility_flags,
76 ),
77 |cx, enum_type_di_node| {
78 // Build the struct type for each variant. These will be referenced by the
79 // DW_TAG_variant DIEs inside of the DW_TAG_variant_part DIE.
80 // We also called the names for the corresponding DW_TAG_variant DIEs here.
81 let variant_member_infos: SmallVec<_> = enum_adt_def
82 .variant_range()
83 .map(|variant_index| VariantMemberInfo {
84 variant_index,
85 variant_name: Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
86 variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node(
87 cx,
88 enum_type_and_layout,
89 enum_type_di_node,
90 variant_index,
91 enum_adt_def.variant(variant_index),
92 enum_type_and_layout.for_variant(cx, variant_index),
93 visibility_flags,
94 ),
95 source_info: if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
96 Some(file_metadata_from_def_id(
97 cx,
98 Some(enum_adt_def.variant(variant_index).def_id),
99 ))
100 } else {
101 None
102 },
103 })
104 .collect();
105
106 let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
107 Some(enum_adt_def.did())
108 } else {
109 None
110 };
111 smallvec![build_enum_variant_part_di_node(
112 cx,
113 enum_type_and_layout,
114 enum_type_di_node,
115 enum_adt_def_id,
116 &variant_member_infos[..],
117 )]
118 },
119 // We don't seem to be emitting generic args on the enum type, it seems. Rather
120 // they get attached to the struct type of each variant.
121 NO_GENERICS,
122 )
123}
124
125/// Build the debuginfo node for a coroutine environment. It looks the same as the debuginfo for
126/// an enum. See [build_enum_type_di_node] for more information.
127///
128/// ```txt
129///
130/// ---> DW_TAG_structure_type (top-level type for the coroutine)
131/// DW_TAG_variant_part (variant part)
132/// DW_AT_discr (reference to discriminant DW_TAG_member)
133/// DW_TAG_member (discriminant member)
134/// DW_TAG_variant (variant 1)
135/// DW_TAG_variant (variant 2)
136/// DW_TAG_variant (variant 3)
137/// DW_TAG_structure_type (type of variant 1)
138/// DW_TAG_structure_type (type of variant 2)
139/// DW_TAG_structure_type (type of variant 3)
140///
141/// ```
142pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
143 cx: &CodegenCx<'ll, 'tcx>,
144 unique_type_id: UniqueTypeId<'tcx>,
145) -> DINodeCreationResult<'ll> {
146 let coroutine_type = unique_type_id.expect_ty();
147 let &ty::Coroutine(coroutine_def_id, coroutine_args) = coroutine_type.kind() else {
148 bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type)
149 };
150
151 let containing_scope = get_namespace_for_item(cx, coroutine_def_id);
152 let coroutine_type_and_layout = cx.layout_of(coroutine_type);
153
154 assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));
155
156 let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
157
158 let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
159 Some(file_metadata_from_def_id(cx, Some(coroutine_def_id)))
160 } else {
161 None
162 };
163
164 type_map::build_type_with_children(
165 cx,
166 type_map::stub(
167 cx,
168 Stub::Struct,
169 unique_type_id,
170 &coroutine_type_name,
171 def_location,
172 size_and_align_of(coroutine_type_and_layout),
173 Some(containing_scope),
174 DIFlags::FlagZero,
175 ),
176 |cx, coroutine_type_di_node| {
177 let coroutine_layout = cx
178 .tcx
179 .coroutine_layout(coroutine_def_id, coroutine_args.as_coroutine().kind_ty())
180 .unwrap();
181
182 let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } =
183 coroutine_type_and_layout.variants
184 else {
185 bug!(
186 "Encountered coroutine with non-direct-tag layout: {:?}",
187 coroutine_type_and_layout
188 )
189 };
190
191 let common_upvar_names =
192 cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id);
193
194 // Build variant struct types
195 let variant_struct_type_di_nodes: SmallVec<_> = variants
196 .indices()
197 .map(|variant_index| {
198 // FIXME: This is problematic because just a number is not a valid identifier.
199 // CoroutineArgs::variant_name(variant_index), would be consistent
200 // with enums?
201 let variant_name = format!("{}", variant_index.as_usize()).into();
202
203 let span = coroutine_layout.variant_source_info[variant_index].span;
204 let source_info = if !span.is_dummy() {
205 let loc = cx.lookup_debug_loc(span.lo());
206 Some((file_metadata(cx, &loc.file), loc.line))
207 } else {
208 None
209 };
210
211 VariantMemberInfo {
212 variant_index,
213 variant_name,
214 variant_struct_type_di_node:
215 super::build_coroutine_variant_struct_type_di_node(
216 cx,
217 variant_index,
218 coroutine_type_and_layout,
219 coroutine_type_di_node,
220 coroutine_layout,
221 common_upvar_names,
222 ),
223 source_info,
224 }
225 })
226 .collect();
227
228 let coroutine_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
229 Some(coroutine_def_id)
230 } else {
231 None
232 };
233 smallvec![build_enum_variant_part_di_node(
234 cx,
235 coroutine_type_and_layout,
236 coroutine_type_di_node,
237 coroutine_def_id,
238 &variant_struct_type_di_nodes[..],
239 )]
240 },
241 // We don't seem to be emitting generic args on the coroutine type, it seems. Rather
242 // they get attached to the struct type of each variant.
243 NO_GENERICS,
244 )
245}
246
247/// Builds the DW_TAG_variant_part of an enum or coroutine debuginfo node:
248///
249/// ```txt
250/// DW_TAG_structure_type (top-level type for enum)
251/// ---> DW_TAG_variant_part (variant part)
252/// DW_AT_discr (reference to discriminant DW_TAG_member)
253/// DW_TAG_member (discriminant member)
254/// DW_TAG_variant (variant 1)
255/// DW_TAG_variant (variant 2)
256/// DW_TAG_variant (variant 3)
257/// DW_TAG_structure_type (type of variant 1)
258/// DW_TAG_structure_type (type of variant 2)
259/// DW_TAG_structure_type (type of variant 3)
260/// ```
261fn build_enum_variant_part_di_node<'ll, 'tcx>(
262 cx: &CodegenCx<'ll, 'tcx>,
263 enum_type_and_layout: TyAndLayout<'tcx>,
264 enum_type_di_node: &'ll DIType,
265 enum_type_def_id: Option<rustc_span::def_id::DefId>,
266 variant_member_infos: &[VariantMemberInfo<'_, 'll>],
267) -> &'ll DIType {
268 let tag_member_di_node =
269 build_discr_member_di_node(cx, enum_type_and_layout, enum_type_di_node);
270
271 let variant_part_unique_type_id =
272 UniqueTypeId::for_enum_variant_part(cx.tcx, enum_type_and_layout.ty);
273
274 let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
275 {
276 file_metadata_from_def_id(cx, enum_type_def_id)
277 } else {
278 (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
279 };
280
281 let stub = StubInfo::new(
282 cx,
283 variant_part_unique_type_id,
284 |cx, variant_part_unique_type_id_str| unsafe {
285 let variant_part_name = "";
286 llvm::LLVMRustDIBuilderCreateVariantPart(
287 DIB(cx),
288 enum_type_di_node,
289 variant_part_name.as_c_char_ptr(),
290 variant_part_name.len(),
291 file_metadata,
292 line_number,
293 enum_type_and_layout.size.bits(),
294 enum_type_and_layout.align.abi.bits() as u32,
295 DIFlags::FlagZero,
296 tag_member_di_node,
297 create_DIArray(DIB(cx), &[]),
298 variant_part_unique_type_id_str.as_c_char_ptr(),
299 variant_part_unique_type_id_str.len(),
300 )
301 },
302 );
303
304 type_map::build_type_with_children(
305 cx,
306 stub,
307 |cx, variant_part_di_node| {
308 variant_member_infos
309 .iter()
310 .map(|variant_member_info| {
311 build_enum_variant_member_di_node(
312 cx,
313 enum_type_and_layout,
314 variant_part_di_node,
315 variant_member_info,
316 )
317 })
318 .collect()
319 },
320 NO_GENERICS,
321 )
322 .di_node
323}
324
325/// Builds the DW_TAG_member describing where we can find the tag of an enum.
326/// Returns `None` if the enum does not have a tag.
327///
328/// ```txt
329///
330/// DW_TAG_structure_type (top-level type for enum)
331/// DW_TAG_variant_part (variant part)
332/// DW_AT_discr (reference to discriminant DW_TAG_member)
333/// ---> DW_TAG_member (discriminant member)
334/// DW_TAG_variant (variant 1)
335/// DW_TAG_variant (variant 2)
336/// DW_TAG_variant (variant 3)
337/// DW_TAG_structure_type (type of variant 1)
338/// DW_TAG_structure_type (type of variant 2)
339/// DW_TAG_structure_type (type of variant 3)
340///
341/// ```
342fn build_discr_member_di_node<'ll, 'tcx>(
343 cx: &CodegenCx<'ll, 'tcx>,
344 enum_or_coroutine_type_and_layout: TyAndLayout<'tcx>,
345 enum_or_coroutine_type_di_node: &'ll DIType,
346) -> Option<&'ll DIType> {
347 let tag_name = match enum_or_coroutine_type_and_layout.ty.kind() {
348 ty::Coroutine(..) => "__state",
349 _ => "",
350 };
351
352 // NOTE: This is actually wrong. This will become a member of
353 // of the DW_TAG_variant_part. But, due to LLVM's API, that
354 // can only be constructed with this DW_TAG_member already in created.
355 // In LLVM IR the wrong scope will be listed but when DWARF is
356 // generated from it, the DW_TAG_member will be a child the
357 // DW_TAG_variant_part.
358 let containing_scope = enum_or_coroutine_type_di_node;
359
360 match enum_or_coroutine_type_and_layout.layout.variants() {
361 // A single-variant or no-variant enum has no discriminant.
362 &Variants::Single { .. } | &Variants::Empty => None,
363
364 &Variants::Multiple { tag_field, .. } => {
365 let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
366 let (size, align) = cx.size_and_align_of(tag_base_type);
367
368 unsafe {
369 Some(llvm::LLVMRustDIBuilderCreateMemberType(
370 DIB(cx),
371 containing_scope,
372 tag_name.as_c_char_ptr(),
373 tag_name.len(),
374 unknown_file_metadata(cx),
375 UNKNOWN_LINE_NUMBER,
376 size.bits(),
377 align.bits() as u32,
378 enum_or_coroutine_type_and_layout.fields.offset(tag_field).bits(),
379 DIFlags::FlagArtificial,
380 type_di_node(cx, tag_base_type),
381 ))
382 }
383 }
384 }
385}
386
387/// Build the debuginfo node for `DW_TAG_variant`:
388///
389/// ```txt
390/// DW_TAG_structure_type (top-level type for enum)
391/// DW_TAG_variant_part (variant part)
392/// DW_AT_discr (reference to discriminant DW_TAG_member)
393/// DW_TAG_member (discriminant member)
394/// ---> DW_TAG_variant (variant 1)
395/// ---> DW_TAG_variant (variant 2)
396/// ---> DW_TAG_variant (variant 3)
397/// DW_TAG_structure_type (type of variant 1)
398/// DW_TAG_structure_type (type of variant 2)
399/// DW_TAG_structure_type (type of variant 3)
400/// ```
401///
402/// This node looks like:
403///
404/// ```txt
405/// DW_TAG_variant
406/// DW_AT_discr_value 0
407/// DW_TAG_member
408/// DW_AT_name None
409/// DW_AT_type <0x000002a1>
410/// DW_AT_alignment 0x00000002
411/// DW_AT_data_member_location 0
412/// ```
413///
414/// The DW_AT_discr_value is optional, and is omitted if
415/// - This is the only variant of a univariant enum (i.e. their is no discriminant)
416/// - This is the "untagged" variant of a niche-layout enum
417/// (where only the other variants are identified by a single value)
418///
419/// There is only ever a single member, the type of which is a struct that describes the
420/// fields of the variant (excluding the discriminant). The name of the member is the name
421/// of the variant as given in the source code. The DW_AT_data_member_location is always
422/// zero.
423///
424/// Note that the LLVM DIBuilder API is a bit unintuitive here. The DW_TAG_variant subtree
425/// (including the DW_TAG_member) is built by a single call to
426/// `LLVMRustDIBuilderCreateVariantMemberType()`.
427fn build_enum_variant_member_di_node<'ll, 'tcx>(
428 cx: &CodegenCx<'ll, 'tcx>,
429 enum_type_and_layout: TyAndLayout<'tcx>,
430 variant_part_di_node: &'ll DIType,
431 variant_member_info: &VariantMemberInfo<'_, 'll>,
432) -> &'ll DIType {
433 let variant_index = variant_member_info.variant_index;
434 let discr_value = super::compute_discriminant_value(cx, enum_type_and_layout, variant_index);
435
436 let (file_di_node, line_number) = variant_member_info
437 .source_info
438 .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
439
440 let discr = discr_value.opt_single_val().map(|value| {
441 let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
442 let size = cx.size_of(tag_base_type);
443 cx.const_uint_big(cx.type_ix(size.bits()), value)
444 });
445
446 unsafe {
447 llvm::LLVMRustDIBuilderCreateVariantMemberType(
448 DIB(cx),
449 variant_part_di_node,
450 variant_member_info.variant_name.as_c_char_ptr(),
451 variant_member_info.variant_name.len(),
452 file_di_node,
453 line_number,
454 enum_type_and_layout.size.bits(),
455 enum_type_and_layout.align.abi.bits() as u32,
456 Size::ZERO.bits(),
457 discr,
458 DIFlags::FlagZero,
459 variant_member_info.variant_struct_type_di_node,
460 )
461 }
462}
463
464/// Information needed for building a `DW_TAG_variant`:
465///
466/// ```txt
467/// DW_TAG_structure_type (top-level type for enum)
468/// DW_TAG_variant_part (variant part)
469/// DW_AT_discr (reference to discriminant DW_TAG_member)
470/// DW_TAG_member (discriminant member)
471/// ---> DW_TAG_variant (variant 1)
472/// ---> DW_TAG_variant (variant 2)
473/// ---> DW_TAG_variant (variant 3)
474/// DW_TAG_structure_type (type of variant 1)
475/// DW_TAG_structure_type (type of variant 2)
476/// DW_TAG_structure_type (type of variant 3)
477/// ```
478struct VariantMemberInfo<'a, 'll> {
479 variant_index: VariantIdx,
480 variant_name: Cow<'a, str>,
481 variant_struct_type_di_node: &'ll DIType,
482 source_info: Option<(&'ll DIFile, c_uint)>,
483}