rustc_codegen_llvm/debuginfo/metadata/enums/
cpp_like.rs

1use std::borrow::Cow;
2
3use libc::c_uint;
4use rustc_abi::{Align, Endian, 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_index::IndexVec;
9use rustc_middle::bug;
10use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
11use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
12use smallvec::smallvec;
13
14use crate::common::{AsCCharPtr, CodegenCx};
15use crate::debuginfo::dwarf_const::DW_TAG_const_type;
16use crate::debuginfo::metadata::enums::DiscrResult;
17use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
18use crate::debuginfo::metadata::{
19    DINodeCreationResult, NO_GENERICS, NO_SCOPE_METADATA, SmallVec, UNKNOWN_LINE_NUMBER,
20    build_field_di_node, file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
21    unknown_file_metadata, visibility_di_flags,
22};
23use crate::debuginfo::utils::DIB;
24use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
25use crate::llvm::{self};
26
27// The names of the associated constants in each variant wrapper struct.
28// These have to match up with the names being used in `intrinsic.natvis`.
29const ASSOC_CONST_DISCR_NAME: &str = "NAME";
30const ASSOC_CONST_DISCR_EXACT: &str = "DISCR_EXACT";
31const ASSOC_CONST_DISCR_BEGIN: &str = "DISCR_BEGIN";
32const ASSOC_CONST_DISCR_END: &str = "DISCR_END";
33
34const ASSOC_CONST_DISCR128_EXACT_LO: &str = "DISCR128_EXACT_LO";
35const ASSOC_CONST_DISCR128_EXACT_HI: &str = "DISCR128_EXACT_HI";
36const ASSOC_CONST_DISCR128_BEGIN_LO: &str = "DISCR128_BEGIN_LO";
37const ASSOC_CONST_DISCR128_BEGIN_HI: &str = "DISCR128_BEGIN_HI";
38const ASSOC_CONST_DISCR128_END_LO: &str = "DISCR128_END_LO";
39const ASSOC_CONST_DISCR128_END_HI: &str = "DISCR128_END_HI";
40
41// The name of the tag field in the top-level union
42const TAG_FIELD_NAME: &str = "tag";
43const TAG_FIELD_NAME_128_LO: &str = "tag128_lo";
44const TAG_FIELD_NAME_128_HI: &str = "tag128_hi";
45
46// We assign a "virtual" discriminant value to the sole variant of
47// a single-variant enum.
48const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0;
49
50/// In CPP-like mode, we generate a union with a field for each variant and an
51/// explicit tag field. The field of each variant has a struct type
52/// that encodes the discriminant of the variant and it's data layout.
53/// The union also has a nested enumeration type that is only used for encoding
54/// variant names in an efficient way. Its enumerator values do _not_ correspond
55/// to the enum's discriminant values.
56/// It's roughly equivalent to the following C/C++ code:
57///
58/// ```c
59/// union enum2$<{fully-qualified-name}> {
60///   struct Variant0 {
61///     struct {name-of-variant-0} {
62///        <variant 0 fields>
63///     } value;
64///
65///     static VariantNames NAME = {name-of-variant-0};
66///     static int_type DISCR_EXACT = {discriminant-of-variant-0};
67///   } variant0;
68///
69///   <other variant structs>
70///
71///   int_type tag;
72///
73///   enum VariantNames {
74///      <name-of-variant-0> = 0, // The numeric values are variant index,
75///      <name-of-variant-1> = 1, // not discriminant values.
76///      <name-of-variant-2> = 2,
77///      ...
78///   }
79/// }
80/// ```
81///
82/// As you can see, the type name is wrapped in `enum2$<_>`. This way we can
83/// have a single NatVis rule for handling all enums. The `2` in `enum2$<_>`
84/// is an encoding version tag, so that debuggers can decide to decode this
85/// differently than the previous `enum$<_>` encoding emitted by earlier
86/// compiler versions.
87///
88/// Niche-tag enums have one special variant, usually called the
89/// "untagged variant". This variant has a field that
90/// doubles as the tag of the enum. The variant is active when the value of
91/// that field is within a pre-defined range. Therefore the variant struct
92/// has a `DISCR_BEGIN` and `DISCR_END` field instead of `DISCR_EXACT` in
93/// that case. Both `DISCR_BEGIN` and `DISCR_END` are inclusive bounds.
94/// Note that these ranges can wrap around, so that `DISCR_END < DISCR_BEGIN`.
95///
96/// Single-variant enums don't actually have a tag field. In this case we
97/// emit a static tag field (that always has the value 0) so we can use the
98/// same representation (and NatVis).
99///
100/// For niche-layout enums it's possible to have a 128-bit tag. NatVis, VS, and
101/// WinDbg (the main targets for CPP-like debuginfo at the moment) don't support
102/// 128-bit integers, so all values involved get split into two 64-bit fields.
103/// Instead of the `tag` field, we generate two fields `tag128_lo` and `tag128_hi`,
104/// Instead of `DISCR_EXACT`, we generate `DISCR128_EXACT_LO` and `DISCR128_EXACT_HI`,
105/// and so on.
106///
107///
108/// The following pseudocode shows how to decode an enum value in a debugger:
109///
110/// ```text
111///
112/// fn find_active_variant(enum_value) -> (VariantName, VariantValue) {
113///     let is_128_bit = enum_value.has_field("tag128_lo");
114///
115///     if !is_128_bit {
116///         // Note: `tag` can be a static field for enums with only one
117///         //       inhabited variant.
118///         let tag = enum_value.field("tag").value;
119///
120///         // For each variant, check if it is a match. Only one of them will match,
121///         // so if we find it we can return it immediately.
122///         for variant_field in enum_value.fields().filter(|f| f.name.starts_with("variant")) {
123///             if variant_field.has_field("DISCR_EXACT") {
124///                 // This variant corresponds to a single tag value
125///                 if variant_field.field("DISCR_EXACT").value == tag {
126///                     return (variant_field.field("NAME"), variant_field.value);
127///                 }
128///             } else {
129///                 // This is a range variant
130///                 let begin = variant_field.field("DISCR_BEGIN");
131///                 let end = variant_field.field("DISCR_END");
132///
133///                 if is_in_range(tag, begin, end) {
134///                     return (variant_field.field("NAME"), variant_field.value);
135///                 }
136///             }
137///         }
138///     } else {
139///         // Basically the same as with smaller tags, we just have to
140///         // stitch the values together.
141///         let tag: u128 = (enum_value.field("tag128_lo").value as u128) |
142///                         (enum_value.field("tag128_hi").value as u128 << 64);
143///
144///         for variant_field in enum_value.fields().filter(|f| f.name.starts_with("variant")) {
145///             if variant_field.has_field("DISCR128_EXACT_LO") {
146///                 let discr_exact = (variant_field.field("DISCR128_EXACT_LO" as u128) |
147///                                   (variant_field.field("DISCR128_EXACT_HI") as u128 << 64);
148///
149///                 // This variant corresponds to a single tag value
150///                 if discr_exact.value == tag {
151///                     return (variant_field.field("NAME"), variant_field.value);
152///                 }
153///             } else {
154///                 // This is a range variant
155///                 let begin = (variant_field.field("DISCR128_BEGIN_LO").value as u128) |
156///                             (variant_field.field("DISCR128_BEGIN_HI").value as u128 << 64);
157///                 let end = (variant_field.field("DISCR128_END_LO").value as u128) |
158///                           (variant_field.field("DISCR128_END_HI").value as u128 << 64);
159///
160///                 if is_in_range(tag, begin, end) {
161///                     return (variant_field.field("NAME"), variant_field.value);
162///                 }
163///             }
164///         }
165///     }
166///
167///     // We should have found an active variant at this point.
168///     unreachable!();
169/// }
170///
171/// // Check if a value is within the given range
172/// // (where the range might wrap around the value space)
173/// fn is_in_range(value, start, end) -> bool {
174///     if start < end {
175///         value >= start && value <= end
176///     } else {
177///         value >= start || value <= end
178///     }
179/// }
180///
181/// ```
182pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
183    cx: &CodegenCx<'ll, 'tcx>,
184    unique_type_id: UniqueTypeId<'tcx>,
185) -> DINodeCreationResult<'ll> {
186    let enum_type = unique_type_id.expect_ty();
187    let &ty::Adt(enum_adt_def, _) = enum_type.kind() else {
188        bug!("build_enum_type_di_node() called with non-enum type: `{:?}`", enum_type)
189    };
190
191    let enum_type_and_layout = cx.layout_of(enum_type);
192    let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
193
194    assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
195
196    let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
197        Some(file_metadata_from_def_id(cx, Some(enum_adt_def.did())))
198    } else {
199        None
200    };
201
202    type_map::build_type_with_children(
203        cx,
204        type_map::stub(
205            cx,
206            type_map::Stub::Union,
207            unique_type_id,
208            &enum_type_name,
209            def_location,
210            cx.size_and_align_of(enum_type),
211            NO_SCOPE_METADATA,
212            visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did()),
213        ),
214        |cx, enum_type_di_node| {
215            match enum_type_and_layout.variants {
216                Variants::Empty => {
217                    // We don't generate any members for uninhabited types.
218                    return smallvec![];
219                }
220                Variants::Single { index: variant_index } => build_single_variant_union_fields(
221                    cx,
222                    enum_adt_def,
223                    enum_type_and_layout,
224                    enum_type_di_node,
225                    variant_index,
226                ),
227                Variants::Multiple {
228                    tag_encoding: TagEncoding::Direct,
229                    ref variants,
230                    tag_field,
231                    ..
232                } => build_union_fields_for_enum(
233                    cx,
234                    enum_adt_def,
235                    enum_type_and_layout,
236                    enum_type_di_node,
237                    variants.indices(),
238                    tag_field,
239                    None,
240                ),
241                Variants::Multiple {
242                    tag_encoding: TagEncoding::Niche { untagged_variant, .. },
243                    ref variants,
244                    tag_field,
245                    ..
246                } => build_union_fields_for_enum(
247                    cx,
248                    enum_adt_def,
249                    enum_type_and_layout,
250                    enum_type_di_node,
251                    variants.indices(),
252                    tag_field,
253                    Some(untagged_variant),
254                ),
255            }
256        },
257        NO_GENERICS,
258    )
259}
260
261/// A coroutine debuginfo node looks the same as a that of an enum type.
262///
263/// See [build_enum_type_di_node] for more information.
264pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
265    cx: &CodegenCx<'ll, 'tcx>,
266    unique_type_id: UniqueTypeId<'tcx>,
267) -> DINodeCreationResult<'ll> {
268    let coroutine_type = unique_type_id.expect_ty();
269    let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
270        let &ty::Coroutine(coroutine_def_id, _) = coroutine_type.kind() else {
271            bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type)
272        };
273        Some(file_metadata_from_def_id(cx, Some(coroutine_def_id)))
274    } else {
275        None
276    };
277    let coroutine_type_and_layout = cx.layout_of(coroutine_type);
278    let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
279
280    assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));
281
282    type_map::build_type_with_children(
283        cx,
284        type_map::stub(
285            cx,
286            type_map::Stub::Union,
287            unique_type_id,
288            &coroutine_type_name,
289            def_location,
290            size_and_align_of(coroutine_type_and_layout),
291            NO_SCOPE_METADATA,
292            DIFlags::FlagZero,
293        ),
294        |cx, coroutine_type_di_node| match coroutine_type_and_layout.variants {
295            Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => {
296                build_union_fields_for_direct_tag_coroutine(
297                    cx,
298                    coroutine_type_and_layout,
299                    coroutine_type_di_node,
300                )
301            }
302            Variants::Single { .. }
303            | Variants::Empty
304            | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => {
305                bug!(
306                    "Encountered coroutine with non-direct-tag layout: {:?}",
307                    coroutine_type_and_layout
308                )
309            }
310        },
311        NO_GENERICS,
312    )
313}
314
315fn build_single_variant_union_fields<'ll, 'tcx>(
316    cx: &CodegenCx<'ll, 'tcx>,
317    enum_adt_def: AdtDef<'tcx>,
318    enum_type_and_layout: TyAndLayout<'tcx>,
319    enum_type_di_node: &'ll DIType,
320    variant_index: VariantIdx,
321) -> SmallVec<&'ll DIType> {
322    let variant_layout = enum_type_and_layout.for_variant(cx, variant_index);
323    let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
324    let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node(
325        cx,
326        enum_type_and_layout,
327        enum_type_di_node,
328        variant_index,
329        enum_adt_def.variant(variant_index),
330        variant_layout,
331        visibility_flags,
332    );
333
334    let tag_base_type = cx.tcx.types.u32;
335    let tag_base_type_di_node = type_di_node(cx, tag_base_type);
336    let tag_base_type_align = cx.align_of(tag_base_type);
337
338    let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
339        Some(enum_adt_def.did())
340    } else {
341        None
342    };
343
344    let variant_names_type_di_node = build_variant_names_type_di_node(
345        cx,
346        enum_type_di_node,
347        std::iter::once((
348            variant_index,
349            Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
350        )),
351        enum_adt_def_id,
352    );
353
354    let variant_struct_type_wrapper_di_node = build_variant_struct_wrapper_type_di_node(
355        cx,
356        enum_type_and_layout,
357        enum_type_di_node,
358        variant_index,
359        None,
360        variant_struct_type_di_node,
361        variant_names_type_di_node,
362        tag_base_type_di_node,
363        tag_base_type,
364        DiscrResult::NoDiscriminant,
365        None,
366    );
367
368    smallvec![
369        build_field_di_node(
370            cx,
371            enum_type_di_node,
372            &variant_union_field_name(variant_index),
373            // NOTE: We use the size and align of the entire type, not from variant_layout
374            //       since the later is sometimes smaller (if it has fewer fields).
375            size_and_align_of(enum_type_and_layout),
376            Size::ZERO,
377            visibility_flags,
378            variant_struct_type_wrapper_di_node,
379            None,
380        ),
381        unsafe {
382            llvm::LLVMRustDIBuilderCreateStaticMemberType(
383                DIB(cx),
384                enum_type_di_node,
385                TAG_FIELD_NAME.as_c_char_ptr(),
386                TAG_FIELD_NAME.len(),
387                unknown_file_metadata(cx),
388                UNKNOWN_LINE_NUMBER,
389                variant_names_type_di_node,
390                visibility_flags,
391                Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)),
392                tag_base_type_align.bits() as u32,
393            )
394        }
395    ]
396}
397
398fn build_union_fields_for_enum<'ll, 'tcx>(
399    cx: &CodegenCx<'ll, 'tcx>,
400    enum_adt_def: AdtDef<'tcx>,
401    enum_type_and_layout: TyAndLayout<'tcx>,
402    enum_type_di_node: &'ll DIType,
403    variant_indices: impl Iterator<Item = VariantIdx> + Clone,
404    tag_field: usize,
405    untagged_variant_index: Option<VariantIdx>,
406) -> SmallVec<&'ll DIType> {
407    let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
408
409    let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
410        Some(enum_adt_def.did())
411    } else {
412        None
413    };
414
415    let variant_names_type_di_node = build_variant_names_type_di_node(
416        cx,
417        enum_type_di_node,
418        variant_indices.clone().map(|variant_index| {
419            let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
420            (variant_index, variant_name)
421        }),
422        enum_adt_def_id,
423    );
424    let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
425
426    let variant_field_infos: SmallVec<VariantFieldInfo<'ll>> = variant_indices
427        .map(|variant_index| {
428            let variant_layout = enum_type_and_layout.for_variant(cx, variant_index);
429
430            let variant_def = enum_adt_def.variant(variant_index);
431
432            let variant_struct_type_di_node = super::build_enum_variant_struct_type_di_node(
433                cx,
434                enum_type_and_layout,
435                enum_type_di_node,
436                variant_index,
437                variant_def,
438                variant_layout,
439                visibility_flags,
440            );
441
442            VariantFieldInfo {
443                variant_index,
444                variant_struct_type_di_node,
445                source_info: None,
446                discr: super::compute_discriminant_value(cx, enum_type_and_layout, variant_index),
447            }
448        })
449        .collect();
450
451    build_union_fields_for_direct_tag_enum_or_coroutine(
452        cx,
453        enum_type_and_layout,
454        enum_type_di_node,
455        &variant_field_infos,
456        variant_names_type_di_node,
457        tag_base_type,
458        tag_field,
459        untagged_variant_index,
460        visibility_flags,
461    )
462}
463
464// The base type of the VariantNames DW_AT_enumeration_type is always the same.
465// It has nothing to do with the tag of the enum and just has to be big enough
466// to hold all variant names.
467fn variant_names_enum_base_type<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> Ty<'tcx> {
468    cx.tcx.types.u32
469}
470
471/// This function builds a DW_AT_enumeration_type that contains an entry for
472/// each variant. Note that this has nothing to do with the discriminant. The
473/// numeric value of each enumerator corresponds to the variant index. The
474/// type is only used for efficiently encoding the name of each variant in
475/// debuginfo.
476fn build_variant_names_type_di_node<'ll, 'tcx>(
477    cx: &CodegenCx<'ll, 'tcx>,
478    containing_scope: &'ll DIType,
479    variants: impl Iterator<Item = (VariantIdx, Cow<'tcx, str>)>,
480    enum_def_id: Option<rustc_span::def_id::DefId>,
481) -> &'ll DIType {
482    // Create an enumerator for each variant.
483    super::build_enumeration_type_di_node(
484        cx,
485        "VariantNames",
486        variant_names_enum_base_type(cx),
487        variants.map(|(variant_index, variant_name)| (variant_name, variant_index.as_u32().into())),
488        enum_def_id,
489        containing_scope,
490    )
491}
492
493fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
494    cx: &CodegenCx<'ll, 'tcx>,
495    enum_or_coroutine_type_and_layout: TyAndLayout<'tcx>,
496    enum_or_coroutine_type_di_node: &'ll DIType,
497    variant_index: VariantIdx,
498    untagged_variant_index: Option<VariantIdx>,
499    variant_struct_type_di_node: &'ll DIType,
500    variant_names_type_di_node: &'ll DIType,
501    tag_base_type_di_node: &'ll DIType,
502    tag_base_type: Ty<'tcx>,
503    discr: DiscrResult,
504    source_info: Option<(&'ll DIFile, c_uint)>,
505) -> &'ll DIType {
506    type_map::build_type_with_children(
507        cx,
508        type_map::stub(
509            cx,
510            Stub::Struct,
511            UniqueTypeId::for_enum_variant_struct_type_wrapper(
512                cx.tcx,
513                enum_or_coroutine_type_and_layout.ty,
514                variant_index,
515            ),
516            &variant_struct_wrapper_type_name(variant_index),
517            source_info,
518            // NOTE: We use size and align of enum_type, not from variant_layout:
519            size_and_align_of(enum_or_coroutine_type_and_layout),
520            Some(enum_or_coroutine_type_di_node),
521            DIFlags::FlagZero,
522        ),
523        |cx, wrapper_struct_type_di_node| {
524            enum DiscrKind {
525                Exact(u64),
526                Exact128(u128),
527                Range(u64, u64),
528                Range128(u128, u128),
529            }
530
531            let (tag_base_type_size, tag_base_type_align) = cx.size_and_align_of(tag_base_type);
532            let is_128_bits = tag_base_type_size.bits() > 64;
533
534            let discr = match discr {
535                DiscrResult::NoDiscriminant => DiscrKind::Exact(SINGLE_VARIANT_VIRTUAL_DISR),
536                DiscrResult::Value(discr_val) => {
537                    if is_128_bits {
538                        DiscrKind::Exact128(discr_val)
539                    } else {
540                        assert_eq!(discr_val, discr_val as u64 as u128);
541                        DiscrKind::Exact(discr_val as u64)
542                    }
543                }
544                DiscrResult::Range(min, max) => {
545                    assert_eq!(Some(variant_index), untagged_variant_index);
546                    if is_128_bits {
547                        DiscrKind::Range128(min, max)
548                    } else {
549                        assert_eq!(min, min as u64 as u128);
550                        assert_eq!(max, max as u64 as u128);
551                        DiscrKind::Range(min as u64, max as u64)
552                    }
553                }
554            };
555
556            let mut fields = SmallVec::new();
557
558            // We always have a field for the value
559            fields.push(build_field_di_node(
560                cx,
561                wrapper_struct_type_di_node,
562                "value",
563                size_and_align_of(enum_or_coroutine_type_and_layout),
564                Size::ZERO,
565                DIFlags::FlagZero,
566                variant_struct_type_di_node,
567                None,
568            ));
569
570            let build_assoc_const = |name: &str,
571                                     type_di_node_: &'ll DIType,
572                                     value: u64,
573                                     align: Align| unsafe {
574                // FIXME: Currently we force all DISCR_* values to be u64's as LLDB seems to have
575                // problems inspecting other value types. Since DISCR_* is typically only going to be
576                // directly inspected via the debugger visualizer - which compares it to the `tag` value
577                // (whose type is not modified at all) it shouldn't cause any real problems.
578                let (t_di, align) = if name == ASSOC_CONST_DISCR_NAME {
579                    (type_di_node_, align.bits() as u32)
580                } else {
581                    let ty_u64 = Ty::new_uint(cx.tcx, ty::UintTy::U64);
582                    (type_di_node(cx, ty_u64), Align::EIGHT.bits() as u32)
583                };
584
585                // must wrap type in a `const` modifier for LLDB to be able to inspect the value of the member
586                let field_type =
587                    llvm::LLVMRustDIBuilderCreateQualifiedType(DIB(cx), DW_TAG_const_type, t_di);
588
589                llvm::LLVMRustDIBuilderCreateStaticMemberType(
590                    DIB(cx),
591                    wrapper_struct_type_di_node,
592                    name.as_c_char_ptr(),
593                    name.len(),
594                    unknown_file_metadata(cx),
595                    UNKNOWN_LINE_NUMBER,
596                    field_type,
597                    DIFlags::FlagZero,
598                    Some(cx.const_u64(value)),
599                    align,
600                )
601            };
602
603            // We also always have an associated constant for the discriminant value
604            // of the variant.
605            fields.push(build_assoc_const(
606                ASSOC_CONST_DISCR_NAME,
607                variant_names_type_di_node,
608                variant_index.as_u32() as u64,
609                cx.align_of(variant_names_enum_base_type(cx)),
610            ));
611
612            // Emit the discriminant value (or range) corresponding to the variant.
613            match discr {
614                DiscrKind::Exact(discr_val) => {
615                    fields.push(build_assoc_const(
616                        ASSOC_CONST_DISCR_EXACT,
617                        tag_base_type_di_node,
618                        discr_val,
619                        tag_base_type_align,
620                    ));
621                }
622                DiscrKind::Exact128(discr_val) => {
623                    let align = cx.align_of(cx.tcx.types.u64);
624                    let type_di_node = type_di_node(cx, cx.tcx.types.u64);
625                    let Split128 { hi, lo } = split_128(discr_val);
626
627                    fields.push(build_assoc_const(
628                        ASSOC_CONST_DISCR128_EXACT_LO,
629                        type_di_node,
630                        lo,
631                        align,
632                    ));
633
634                    fields.push(build_assoc_const(
635                        ASSOC_CONST_DISCR128_EXACT_HI,
636                        type_di_node,
637                        hi,
638                        align,
639                    ));
640                }
641                DiscrKind::Range(begin, end) => {
642                    fields.push(build_assoc_const(
643                        ASSOC_CONST_DISCR_BEGIN,
644                        tag_base_type_di_node,
645                        begin,
646                        tag_base_type_align,
647                    ));
648
649                    fields.push(build_assoc_const(
650                        ASSOC_CONST_DISCR_END,
651                        tag_base_type_di_node,
652                        end,
653                        tag_base_type_align,
654                    ));
655                }
656                DiscrKind::Range128(begin, end) => {
657                    let align = cx.align_of(cx.tcx.types.u64);
658                    let type_di_node = type_di_node(cx, cx.tcx.types.u64);
659                    let Split128 { hi: begin_hi, lo: begin_lo } = split_128(begin);
660                    let Split128 { hi: end_hi, lo: end_lo } = split_128(end);
661
662                    fields.push(build_assoc_const(
663                        ASSOC_CONST_DISCR128_BEGIN_HI,
664                        type_di_node,
665                        begin_hi,
666                        align,
667                    ));
668
669                    fields.push(build_assoc_const(
670                        ASSOC_CONST_DISCR128_BEGIN_LO,
671                        type_di_node,
672                        begin_lo,
673                        align,
674                    ));
675
676                    fields.push(build_assoc_const(
677                        ASSOC_CONST_DISCR128_END_HI,
678                        type_di_node,
679                        end_hi,
680                        align,
681                    ));
682
683                    fields.push(build_assoc_const(
684                        ASSOC_CONST_DISCR128_END_LO,
685                        type_di_node,
686                        end_lo,
687                        align,
688                    ));
689                }
690            }
691
692            fields
693        },
694        NO_GENERICS,
695    )
696    .di_node
697}
698
699struct Split128 {
700    hi: u64,
701    lo: u64,
702}
703
704fn split_128(value: u128) -> Split128 {
705    Split128 { hi: (value >> 64) as u64, lo: value as u64 }
706}
707
708fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
709    cx: &CodegenCx<'ll, 'tcx>,
710    coroutine_type_and_layout: TyAndLayout<'tcx>,
711    coroutine_type_di_node: &'ll DIType,
712) -> SmallVec<&'ll DIType> {
713    let Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } =
714        coroutine_type_and_layout.variants
715    else {
716        bug!("This function only supports layouts with directly encoded tags.")
717    };
718
719    let (coroutine_def_id, coroutine_args) = match coroutine_type_and_layout.ty.kind() {
720        &ty::Coroutine(def_id, args) => (def_id, args.as_coroutine()),
721        _ => unreachable!(),
722    };
723
724    let coroutine_layout =
725        cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args.kind_ty()).unwrap();
726
727    let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id);
728    let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);
729    let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len();
730
731    let tag_base_type = tag_base_type(cx.tcx, coroutine_type_and_layout);
732
733    let variant_names_type_di_node = build_variant_names_type_di_node(
734        cx,
735        coroutine_type_di_node,
736        variant_range
737            .clone()
738            .map(|variant_index| (variant_index, CoroutineArgs::variant_name(variant_index))),
739        if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
740            Some(coroutine_def_id)
741        } else {
742            None
743        },
744    );
745
746    let discriminants: IndexVec<VariantIdx, DiscrResult> = {
747        let discriminants_iter = coroutine_args.discriminants(coroutine_def_id, cx.tcx);
748        let mut discriminants: IndexVec<VariantIdx, DiscrResult> =
749            IndexVec::with_capacity(variant_count);
750        for (variant_index, discr) in discriminants_iter {
751            // Assert that the index in the IndexMap matches up with the given VariantIdx.
752            assert_eq!(variant_index, discriminants.next_index());
753            discriminants.push(DiscrResult::Value(discr.val));
754        }
755        discriminants
756    };
757
758    // Build the type node for each field.
759    let variant_field_infos: SmallVec<VariantFieldInfo<'ll>> = variant_range
760        .map(|variant_index| {
761            let variant_struct_type_di_node = super::build_coroutine_variant_struct_type_di_node(
762                cx,
763                variant_index,
764                coroutine_type_and_layout,
765                coroutine_type_di_node,
766                coroutine_layout,
767                common_upvar_names,
768            );
769
770            let span = coroutine_layout.variant_source_info[variant_index].span;
771            let source_info = if !span.is_dummy() {
772                let loc = cx.lookup_debug_loc(span.lo());
773                Some((file_metadata(cx, &loc.file), loc.line as c_uint))
774            } else {
775                None
776            };
777
778            VariantFieldInfo {
779                variant_index,
780                variant_struct_type_di_node,
781                source_info,
782                discr: discriminants[variant_index],
783            }
784        })
785        .collect();
786
787    build_union_fields_for_direct_tag_enum_or_coroutine(
788        cx,
789        coroutine_type_and_layout,
790        coroutine_type_di_node,
791        &variant_field_infos[..],
792        variant_names_type_di_node,
793        tag_base_type,
794        tag_field,
795        None,
796        DIFlags::FlagZero,
797    )
798}
799
800/// This is a helper function shared between enums and coroutines that makes sure fields have the
801/// expect names.
802fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
803    cx: &CodegenCx<'ll, 'tcx>,
804    enum_type_and_layout: TyAndLayout<'tcx>,
805    enum_type_di_node: &'ll DIType,
806    variant_field_infos: &[VariantFieldInfo<'ll>],
807    discr_type_di_node: &'ll DIType,
808    tag_base_type: Ty<'tcx>,
809    tag_field: usize,
810    untagged_variant_index: Option<VariantIdx>,
811    di_flags: DIFlags,
812) -> SmallVec<&'ll DIType> {
813    let tag_base_type_di_node = type_di_node(cx, tag_base_type);
814    let mut unions_fields = SmallVec::with_capacity(variant_field_infos.len() + 1);
815
816    // We create a field in the union for each variant ...
817    unions_fields.extend(variant_field_infos.into_iter().map(|variant_member_info| {
818        let (file_di_node, line_number) = variant_member_info
819            .source_info
820            .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
821
822        let field_name = variant_union_field_name(variant_member_info.variant_index);
823        let (size, align) = size_and_align_of(enum_type_and_layout);
824
825        let variant_struct_type_wrapper = build_variant_struct_wrapper_type_di_node(
826            cx,
827            enum_type_and_layout,
828            enum_type_di_node,
829            variant_member_info.variant_index,
830            untagged_variant_index,
831            variant_member_info.variant_struct_type_di_node,
832            discr_type_di_node,
833            tag_base_type_di_node,
834            tag_base_type,
835            variant_member_info.discr,
836            if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
837                variant_member_info.source_info
838            } else {
839                None
840            },
841        );
842
843        // We use LLVMRustDIBuilderCreateMemberType() member type directly because
844        // the build_field_di_node() function does not support specifying a source location,
845        // which is something that we don't do anywhere else.
846        unsafe {
847            llvm::LLVMRustDIBuilderCreateMemberType(
848                DIB(cx),
849                enum_type_di_node,
850                field_name.as_c_char_ptr(),
851                field_name.len(),
852                file_di_node,
853                line_number,
854                // NOTE: We use the size and align of the entire type, not from variant_layout
855                //       since the later is sometimes smaller (if it has fewer fields).
856                size.bits(),
857                align.bits() as u32,
858                // Union fields are always at offset zero
859                Size::ZERO.bits(),
860                di_flags,
861                variant_struct_type_wrapper,
862            )
863        }
864    }));
865
866    assert_eq!(
867        cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
868        cx.size_and_align_of(self::tag_base_type(cx.tcx, enum_type_and_layout))
869    );
870
871    // ... and a field for the tag. If the tag is 128 bits wide, this will actually
872    // be two 64-bit fields.
873    let is_128_bits = cx.size_of(tag_base_type).bits() > 64;
874
875    if is_128_bits {
876        let type_di_node = type_di_node(cx, cx.tcx.types.u64);
877        let size_and_align = cx.size_and_align_of(cx.tcx.types.u64);
878
879        let (lo_offset, hi_offset) = match cx.tcx.data_layout.endian {
880            Endian::Little => (0, 8),
881            Endian::Big => (8, 0),
882        };
883
884        let tag_field_offset = enum_type_and_layout.fields.offset(tag_field).bytes();
885        let lo_offset = Size::from_bytes(tag_field_offset + lo_offset);
886        let hi_offset = Size::from_bytes(tag_field_offset + hi_offset);
887
888        unions_fields.push(build_field_di_node(
889            cx,
890            enum_type_di_node,
891            TAG_FIELD_NAME_128_LO,
892            size_and_align,
893            lo_offset,
894            di_flags,
895            type_di_node,
896            None,
897        ));
898
899        unions_fields.push(build_field_di_node(
900            cx,
901            enum_type_di_node,
902            TAG_FIELD_NAME_128_HI,
903            size_and_align,
904            hi_offset,
905            DIFlags::FlagZero,
906            type_di_node,
907            None,
908        ));
909    } else {
910        unions_fields.push(build_field_di_node(
911            cx,
912            enum_type_di_node,
913            TAG_FIELD_NAME,
914            cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
915            enum_type_and_layout.fields.offset(tag_field),
916            di_flags,
917            tag_base_type_di_node,
918            None,
919        ));
920    }
921
922    unions_fields
923}
924
925/// Information about a single field of the top-level DW_TAG_union_type.
926struct VariantFieldInfo<'ll> {
927    variant_index: VariantIdx,
928    variant_struct_type_di_node: &'ll DIType,
929    source_info: Option<(&'ll DIFile, c_uint)>,
930    discr: DiscrResult,
931}
932
933fn variant_union_field_name(variant_index: VariantIdx) -> Cow<'static, str> {
934    const PRE_ALLOCATED: [&str; 16] = [
935        "variant0",
936        "variant1",
937        "variant2",
938        "variant3",
939        "variant4",
940        "variant5",
941        "variant6",
942        "variant7",
943        "variant8",
944        "variant9",
945        "variant10",
946        "variant11",
947        "variant12",
948        "variant13",
949        "variant14",
950        "variant15",
951    ];
952
953    PRE_ALLOCATED
954        .get(variant_index.as_usize())
955        .map(|&s| Cow::from(s))
956        .unwrap_or_else(|| format!("variant{}", variant_index.as_usize()).into())
957}
958
959fn variant_struct_wrapper_type_name(variant_index: VariantIdx) -> Cow<'static, str> {
960    const PRE_ALLOCATED: [&str; 16] = [
961        "Variant0",
962        "Variant1",
963        "Variant2",
964        "Variant3",
965        "Variant4",
966        "Variant5",
967        "Variant6",
968        "Variant7",
969        "Variant8",
970        "Variant9",
971        "Variant10",
972        "Variant11",
973        "Variant12",
974        "Variant13",
975        "Variant14",
976        "Variant15",
977    ];
978
979    PRE_ALLOCATED
980        .get(variant_index.as_usize())
981        .map(|&s| Cow::from(s))
982        .unwrap_or_else(|| format!("Variant{}", variant_index.as_usize()).into())
983}