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}