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}