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, create_member_type,
17 file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
18 unknown_file_metadata, 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 =
178 cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args).unwrap();
179
180 let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } =
181 coroutine_type_and_layout.variants
182 else {
183 bug!(
184 "Encountered coroutine with non-direct-tag layout: {:?}",
185 coroutine_type_and_layout
186 )
187 };
188
189 let common_upvar_names =
190 cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id);
191
192 // Build variant struct types
193 let variant_struct_type_di_nodes: SmallVec<_> = variants
194 .indices()
195 .map(|variant_index| {
196 // FIXME: This is problematic because just a number is not a valid identifier.
197 // CoroutineArgs::variant_name(variant_index), would be consistent
198 // with enums?
199 let variant_name = format!("{}", variant_index.as_usize()).into();
200
201 let span = coroutine_layout.variant_source_info[variant_index].span;
202 let source_info = if !span.is_dummy() {
203 let loc = cx.lookup_debug_loc(span.lo());
204 Some((file_metadata(cx, &loc.file), loc.line))
205 } else {
206 None
207 };
208
209 VariantMemberInfo {
210 variant_index,
211 variant_name,
212 variant_struct_type_di_node:
213 super::build_coroutine_variant_struct_type_di_node(
214 cx,
215 variant_index,
216 coroutine_type_and_layout,
217 coroutine_type_di_node,
218 coroutine_layout,
219 common_upvar_names,
220 ),
221 source_info,
222 }
223 })
224 .collect();
225
226 let coroutine_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
227 Some(coroutine_def_id)
228 } else {
229 None
230 };
231 smallvec![build_enum_variant_part_di_node(
232 cx,
233 coroutine_type_and_layout,
234 coroutine_type_di_node,
235 coroutine_def_id,
236 &variant_struct_type_di_nodes[..],
237 )]
238 },
239 // We don't seem to be emitting generic args on the coroutine type, it seems. Rather
240 // they get attached to the struct type of each variant.
241 NO_GENERICS,
242 )
243}
244
245/// Builds the DW_TAG_variant_part of an enum or coroutine debuginfo node:
246///
247/// ```txt
248/// DW_TAG_structure_type (top-level type for enum)
249/// ---> DW_TAG_variant_part (variant part)
250/// DW_AT_discr (reference to discriminant DW_TAG_member)
251/// DW_TAG_member (discriminant member)
252/// DW_TAG_variant (variant 1)
253/// DW_TAG_variant (variant 2)
254/// DW_TAG_variant (variant 3)
255/// DW_TAG_structure_type (type of variant 1)
256/// DW_TAG_structure_type (type of variant 2)
257/// DW_TAG_structure_type (type of variant 3)
258/// ```
259fn build_enum_variant_part_di_node<'ll, 'tcx>(
260 cx: &CodegenCx<'ll, 'tcx>,
261 enum_type_and_layout: TyAndLayout<'tcx>,
262 enum_type_di_node: &'ll DIType,
263 enum_type_def_id: Option<rustc_span::def_id::DefId>,
264 variant_member_infos: &[VariantMemberInfo<'_, 'll>],
265) -> &'ll DIType {
266 let tag_member_di_node =
267 build_discr_member_di_node(cx, enum_type_and_layout, enum_type_di_node);
268
269 let variant_part_unique_type_id =
270 UniqueTypeId::for_enum_variant_part(cx.tcx, enum_type_and_layout.ty);
271
272 let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
273 {
274 file_metadata_from_def_id(cx, enum_type_def_id)
275 } else {
276 (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
277 };
278
279 let stub = StubInfo::new(
280 cx,
281 variant_part_unique_type_id,
282 |cx, variant_part_unique_type_id_str| unsafe {
283 let variant_part_name = "";
284 llvm::LLVMRustDIBuilderCreateVariantPart(
285 DIB(cx),
286 enum_type_di_node,
287 variant_part_name.as_c_char_ptr(),
288 variant_part_name.len(),
289 file_metadata,
290 line_number,
291 enum_type_and_layout.size.bits(),
292 enum_type_and_layout.align.abi.bits() as u32,
293 DIFlags::FlagZero,
294 tag_member_di_node,
295 create_DIArray(DIB(cx), &[]),
296 variant_part_unique_type_id_str.as_c_char_ptr(),
297 variant_part_unique_type_id_str.len(),
298 )
299 },
300 );
301
302 type_map::build_type_with_children(
303 cx,
304 stub,
305 |cx, variant_part_di_node| {
306 variant_member_infos
307 .iter()
308 .map(|variant_member_info| {
309 build_enum_variant_member_di_node(
310 cx,
311 enum_type_and_layout,
312 variant_part_di_node,
313 variant_member_info,
314 )
315 })
316 .collect()
317 },
318 NO_GENERICS,
319 )
320 .di_node
321}
322
323/// Builds the DW_TAG_member describing where we can find the tag of an enum.
324/// Returns `None` if the enum does not have a tag.
325///
326/// ```txt
327///
328/// DW_TAG_structure_type (top-level type for enum)
329/// DW_TAG_variant_part (variant part)
330/// DW_AT_discr (reference to discriminant DW_TAG_member)
331/// ---> DW_TAG_member (discriminant member)
332/// DW_TAG_variant (variant 1)
333/// DW_TAG_variant (variant 2)
334/// DW_TAG_variant (variant 3)
335/// DW_TAG_structure_type (type of variant 1)
336/// DW_TAG_structure_type (type of variant 2)
337/// DW_TAG_structure_type (type of variant 3)
338///
339/// ```
340fn build_discr_member_di_node<'ll, 'tcx>(
341 cx: &CodegenCx<'ll, 'tcx>,
342 enum_or_coroutine_type_and_layout: TyAndLayout<'tcx>,
343 enum_or_coroutine_type_di_node: &'ll DIType,
344) -> Option<&'ll DIType> {
345 let tag_name = match enum_or_coroutine_type_and_layout.ty.kind() {
346 ty::Coroutine(..) => "__state",
347 _ => "",
348 };
349
350 // NOTE: This is actually wrong. This will become a member of
351 // of the DW_TAG_variant_part. But, due to LLVM's API, that
352 // can only be constructed with this DW_TAG_member already in created.
353 // In LLVM IR the wrong scope will be listed but when DWARF is
354 // generated from it, the DW_TAG_member will be a child the
355 // DW_TAG_variant_part.
356 let containing_scope = enum_or_coroutine_type_di_node;
357
358 match enum_or_coroutine_type_and_layout.layout.variants() {
359 // A single-variant or no-variant enum has no discriminant.
360 &Variants::Single { .. } | &Variants::Empty => None,
361
362 &Variants::Multiple { tag_field, .. } => {
363 let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
364 let ty = type_di_node(cx, tag_base_type);
365 let file = unknown_file_metadata(cx);
366
367 let layout = cx.layout_of(tag_base_type);
368
369 Some(create_member_type(
370 cx,
371 containing_scope,
372 &tag_name,
373 file,
374 UNKNOWN_LINE_NUMBER,
375 layout,
376 enum_or_coroutine_type_and_layout.fields.offset(tag_field.as_usize()),
377 DIFlags::FlagArtificial,
378 ty,
379 ))
380 }
381 }
382}
383
384/// Build the debuginfo node for `DW_TAG_variant`:
385///
386/// ```txt
387/// DW_TAG_structure_type (top-level type for enum)
388/// DW_TAG_variant_part (variant part)
389/// DW_AT_discr (reference to discriminant DW_TAG_member)
390/// DW_TAG_member (discriminant member)
391/// ---> DW_TAG_variant (variant 1)
392/// ---> DW_TAG_variant (variant 2)
393/// ---> DW_TAG_variant (variant 3)
394/// DW_TAG_structure_type (type of variant 1)
395/// DW_TAG_structure_type (type of variant 2)
396/// DW_TAG_structure_type (type of variant 3)
397/// ```
398///
399/// This node looks like:
400///
401/// ```txt
402/// DW_TAG_variant
403/// DW_AT_discr_value 0
404/// DW_TAG_member
405/// DW_AT_name None
406/// DW_AT_type <0x000002a1>
407/// DW_AT_alignment 0x00000002
408/// DW_AT_data_member_location 0
409/// ```
410///
411/// The DW_AT_discr_value is optional, and is omitted if
412/// - This is the only variant of a univariant enum (i.e. their is no discriminant)
413/// - This is the "untagged" variant of a niche-layout enum
414/// (where only the other variants are identified by a single value)
415///
416/// There is only ever a single member, the type of which is a struct that describes the
417/// fields of the variant (excluding the discriminant). The name of the member is the name
418/// of the variant as given in the source code. The DW_AT_data_member_location is always
419/// zero.
420///
421/// Note that the LLVM DIBuilder API is a bit unintuitive here. The DW_TAG_variant subtree
422/// (including the DW_TAG_member) is built by a single call to
423/// `LLVMRustDIBuilderCreateVariantMemberType()`.
424fn build_enum_variant_member_di_node<'ll, 'tcx>(
425 cx: &CodegenCx<'ll, 'tcx>,
426 enum_type_and_layout: TyAndLayout<'tcx>,
427 variant_part_di_node: &'ll DIType,
428 variant_member_info: &VariantMemberInfo<'_, 'll>,
429) -> &'ll DIType {
430 let variant_index = variant_member_info.variant_index;
431 let discr_value = super::compute_discriminant_value(cx, enum_type_and_layout, variant_index);
432
433 let (file_di_node, line_number) = variant_member_info
434 .source_info
435 .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
436
437 let discr = discr_value.opt_single_val().map(|value| {
438 let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
439 let size = cx.size_of(tag_base_type);
440 cx.const_uint_big(cx.type_ix(size.bits()), value)
441 });
442
443 unsafe {
444 llvm::LLVMRustDIBuilderCreateVariantMemberType(
445 DIB(cx),
446 variant_part_di_node,
447 variant_member_info.variant_name.as_c_char_ptr(),
448 variant_member_info.variant_name.len(),
449 file_di_node,
450 line_number,
451 enum_type_and_layout.size.bits(),
452 enum_type_and_layout.align.abi.bits() as u32,
453 Size::ZERO.bits(),
454 discr,
455 DIFlags::FlagZero,
456 variant_member_info.variant_struct_type_di_node,
457 )
458 }
459}
460
461/// Information needed for building a `DW_TAG_variant`:
462///
463/// ```txt
464/// DW_TAG_structure_type (top-level type for enum)
465/// DW_TAG_variant_part (variant part)
466/// DW_AT_discr (reference to discriminant DW_TAG_member)
467/// DW_TAG_member (discriminant member)
468/// ---> DW_TAG_variant (variant 1)
469/// ---> DW_TAG_variant (variant 2)
470/// ---> DW_TAG_variant (variant 3)
471/// DW_TAG_structure_type (type of variant 1)
472/// DW_TAG_structure_type (type of variant 2)
473/// DW_TAG_structure_type (type of variant 3)
474/// ```
475struct VariantMemberInfo<'a, 'll> {
476 variant_index: VariantIdx,
477 variant_name: Cow<'a, str>,
478 variant_struct_type_di_node: &'ll DIType,
479 source_info: Option<(&'ll DIFile, c_uint)>,
480}