rustc_codegen_llvm/debuginfo/metadata/enums/
mod.rs

1use std::borrow::Cow;
2
3use rustc_abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
4use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_like_debuginfo};
5use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
6use rustc_codegen_ssa::traits::MiscCodegenMethods;
7use rustc_hir::def::CtorKind;
8use rustc_index::IndexSlice;
9use rustc_middle::bug;
10use rustc_middle::mir::CoroutineLayout;
11use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
12use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef};
13use rustc_span::{Span, Symbol};
14
15use super::type_map::{DINodeCreationResult, UniqueTypeId};
16use super::{SmallVec, size_and_align_of};
17use crate::common::{AsCCharPtr, CodegenCx};
18use crate::debuginfo::metadata::type_map::{self, Stub};
19use crate::debuginfo::metadata::{
20    UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes,
21    file_metadata_from_def_id, type_di_node, unknown_file_metadata,
22};
23use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
24use crate::llvm::debuginfo::{DIFlags, DIType};
25use crate::llvm::{self};
26
27mod cpp_like;
28mod native;
29
30pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
31    cx: &CodegenCx<'ll, 'tcx>,
32    unique_type_id: UniqueTypeId<'tcx>,
33    span: Span,
34) -> DINodeCreationResult<'ll> {
35    let enum_type = unique_type_id.expect_ty();
36    let &ty::Adt(enum_adt_def, _) = enum_type.kind() else {
37        bug!("build_enum_type_di_node() called with non-enum type: `{:?}`", enum_type)
38    };
39
40    let enum_type_and_layout = cx.spanned_layout_of(enum_type, span);
41
42    if wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout) {
43        return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout);
44    }
45
46    if cpp_like_debuginfo(cx.tcx) {
47        cpp_like::build_enum_type_di_node(cx, unique_type_id)
48    } else {
49        native::build_enum_type_di_node(cx, unique_type_id)
50    }
51}
52
53pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
54    cx: &CodegenCx<'ll, 'tcx>,
55    unique_type_id: UniqueTypeId<'tcx>,
56) -> DINodeCreationResult<'ll> {
57    if cpp_like_debuginfo(cx.tcx) {
58        cpp_like::build_coroutine_di_node(cx, unique_type_id)
59    } else {
60        native::build_coroutine_di_node(cx, unique_type_id)
61    }
62}
63
64/// Build the debuginfo node for a C-style enum, i.e. an enum the variants of which have no fields.
65///
66/// The resulting debuginfo will be a DW_TAG_enumeration_type.
67fn build_c_style_enum_di_node<'ll, 'tcx>(
68    cx: &CodegenCx<'ll, 'tcx>,
69    enum_adt_def: AdtDef<'tcx>,
70    enum_type_and_layout: TyAndLayout<'tcx>,
71) -> DINodeCreationResult<'ll> {
72    let containing_scope = get_namespace_for_item(cx, enum_adt_def.did());
73    let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
74        Some(enum_adt_def.did())
75    } else {
76        None
77    };
78    DINodeCreationResult {
79        di_node: build_enumeration_type_di_node(
80            cx,
81            &compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
82            tag_base_type(cx.tcx, enum_type_and_layout),
83            enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
84                let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
85                (name, discr.val)
86            }),
87            enum_adt_def_id,
88            containing_scope,
89        ),
90        already_stored_in_typemap: false,
91    }
92}
93
94/// Build a DW_TAG_enumeration_type debuginfo node, with the given base type and variants.
95/// This is a helper function and does not register anything in the type map by itself.
96///
97/// `variants` is an iterator of (discr-value, variant-name).
98fn build_enumeration_type_di_node<'ll, 'tcx>(
99    cx: &CodegenCx<'ll, 'tcx>,
100    type_name: &str,
101    base_type: Ty<'tcx>,
102    enumerators: impl Iterator<Item = (Cow<'tcx, str>, u128)>,
103    def_id: Option<rustc_span::def_id::DefId>,
104    containing_scope: &'ll DIType,
105) -> &'ll DIType {
106    let is_unsigned = match base_type.kind() {
107        ty::Int(_) => false,
108        ty::Uint(_) => true,
109        _ => bug!("build_enumeration_type_di_node() called with non-integer tag type."),
110    };
111    let (size, align) = cx.size_and_align_of(base_type);
112
113    let enumerator_di_nodes: SmallVec<Option<&'ll DIType>> = enumerators
114        .map(|(name, value)| unsafe {
115            let value = [value as u64, (value >> 64) as u64];
116            Some(llvm::LLVMRustDIBuilderCreateEnumerator(
117                DIB(cx),
118                name.as_c_char_ptr(),
119                name.len(),
120                value.as_ptr(),
121                size.bits() as libc::c_uint,
122                is_unsigned,
123            ))
124        })
125        .collect();
126
127    let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
128    {
129        file_metadata_from_def_id(cx, def_id)
130    } else {
131        (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
132    };
133
134    unsafe {
135        llvm::LLVMRustDIBuilderCreateEnumerationType(
136            DIB(cx),
137            containing_scope,
138            type_name.as_c_char_ptr(),
139            type_name.len(),
140            file_metadata,
141            line_number,
142            size.bits(),
143            align.bits() as u32,
144            create_DIArray(DIB(cx), &enumerator_di_nodes[..]),
145            type_di_node(cx, base_type),
146            true,
147        )
148    }
149}
150
151/// Build the debuginfo node for the struct type describing a single variant of an enum.
152///
153/// ```txt
154///       DW_TAG_structure_type              (top-level type for enum)
155///         DW_TAG_variant_part              (variant part)
156///           DW_AT_discr                    (reference to discriminant DW_TAG_member)
157///           DW_TAG_member                  (discriminant member)
158///           DW_TAG_variant                 (variant 1)
159///           DW_TAG_variant                 (variant 2)
160///           DW_TAG_variant                 (variant 3)
161///  --->   DW_TAG_structure_type            (type of variant 1)
162///  --->   DW_TAG_structure_type            (type of variant 2)
163///  --->   DW_TAG_structure_type            (type of variant 3)
164/// ```
165///
166/// In CPP-like mode, we have the exact same descriptions for each variant too:
167///
168/// ```txt
169///       DW_TAG_union_type              (top-level type for enum)
170///         DW_TAG_member                    (member for variant 1)
171///         DW_TAG_member                    (member for variant 2)
172///         DW_TAG_member                    (member for variant 3)
173///  --->   DW_TAG_structure_type            (type of variant 1)
174///  --->   DW_TAG_structure_type            (type of variant 2)
175///  --->   DW_TAG_structure_type            (type of variant 3)
176///         DW_TAG_enumeration_type          (type of tag)
177/// ```
178///
179/// The node looks like:
180///
181/// ```txt
182/// DW_TAG_structure_type
183///   DW_AT_name                  <name-of-variant>
184///   DW_AT_byte_size             0x00000010
185///   DW_AT_alignment             0x00000008
186///   DW_TAG_member
187///     DW_AT_name                  <name-of-field-0>
188///     DW_AT_type                  <0x0000018e>
189///     DW_AT_alignment             0x00000004
190///     DW_AT_data_member_location  4
191///   DW_TAG_member
192///     DW_AT_name                  <name-of-field-1>
193///     DW_AT_type                  <0x00000195>
194///     DW_AT_alignment             0x00000008
195///     DW_AT_data_member_location  8
196///   ...
197/// ```
198///
199/// The type of a variant is always a struct type with the name of the variant
200/// and a DW_TAG_member for each field (but not the discriminant).
201fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
202    cx: &CodegenCx<'ll, 'tcx>,
203    enum_type_and_layout: TyAndLayout<'tcx>,
204    enum_type_di_node: &'ll DIType,
205    variant_index: VariantIdx,
206    variant_def: &VariantDef,
207    variant_layout: TyAndLayout<'tcx>,
208    di_flags: DIFlags,
209) -> &'ll DIType {
210    assert_eq!(variant_layout.ty, enum_type_and_layout.ty);
211
212    let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
213        Some(file_metadata_from_def_id(cx, Some(variant_def.def_id)))
214    } else {
215        None
216    };
217
218    type_map::build_type_with_children(
219        cx,
220        type_map::stub(
221            cx,
222            Stub::Struct,
223            UniqueTypeId::for_enum_variant_struct_type(
224                cx.tcx,
225                enum_type_and_layout.ty,
226                variant_index,
227            ),
228            variant_def.name.as_str(),
229            def_location,
230            // NOTE: We use size and align of enum_type, not from variant_layout:
231            size_and_align_of(enum_type_and_layout),
232            Some(enum_type_di_node),
233            di_flags,
234        ),
235        |cx, struct_type_di_node| {
236            (0..variant_layout.fields.count())
237                .map(|field_index| {
238                    let field_name = if variant_def.ctor_kind() != Some(CtorKind::Fn) {
239                        // Fields have names
240                        let field = &variant_def.fields[FieldIdx::from_usize(field_index)];
241                        Cow::from(field.name.as_str())
242                    } else {
243                        // Tuple-like
244                        super::tuple_field_name(field_index)
245                    };
246
247                    let field_layout = variant_layout.field(cx, field_index);
248
249                    build_field_di_node(
250                        cx,
251                        struct_type_di_node,
252                        &field_name,
253                        field_layout,
254                        variant_layout.fields.offset(field_index),
255                        di_flags,
256                        type_di_node(cx, field_layout.ty),
257                        None,
258                    )
259                })
260                .collect::<SmallVec<_>>()
261        },
262        |cx| build_generic_type_param_di_nodes(cx, enum_type_and_layout.ty),
263    )
264    .di_node
265}
266
267/// Build the struct type for describing a single coroutine state.
268/// See [build_coroutine_variant_struct_type_di_node].
269///
270/// ```txt
271///
272///       DW_TAG_structure_type              (top-level type for enum)
273///         DW_TAG_variant_part              (variant part)
274///           DW_AT_discr                    (reference to discriminant DW_TAG_member)
275///           DW_TAG_member                  (discriminant member)
276///           DW_TAG_variant                 (variant 1)
277///           DW_TAG_variant                 (variant 2)
278///           DW_TAG_variant                 (variant 3)
279///  --->   DW_TAG_structure_type            (type of variant 1)
280///  --->   DW_TAG_structure_type            (type of variant 2)
281///  --->   DW_TAG_structure_type            (type of variant 3)
282///
283/// ```
284fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
285    cx: &CodegenCx<'ll, 'tcx>,
286    variant_index: VariantIdx,
287    coroutine_type_and_layout: TyAndLayout<'tcx>,
288    coroutine_type_di_node: &'ll DIType,
289    coroutine_layout: &CoroutineLayout<'tcx>,
290    common_upvar_names: &IndexSlice<FieldIdx, Symbol>,
291) -> &'ll DIType {
292    let variant_name = CoroutineArgs::variant_name(variant_index);
293    let unique_type_id = UniqueTypeId::for_enum_variant_struct_type(
294        cx.tcx,
295        coroutine_type_and_layout.ty,
296        variant_index,
297    );
298
299    let variant_layout = coroutine_type_and_layout.for_variant(cx, variant_index);
300
301    let coroutine_args = match coroutine_type_and_layout.ty.kind() {
302        ty::Coroutine(_, args) => args.as_coroutine(),
303        _ => unreachable!(),
304    };
305
306    type_map::build_type_with_children(
307        cx,
308        type_map::stub(
309            cx,
310            Stub::Struct,
311            unique_type_id,
312            &variant_name,
313            None,
314            size_and_align_of(coroutine_type_and_layout),
315            Some(coroutine_type_di_node),
316            DIFlags::FlagZero,
317        ),
318        |cx, variant_struct_type_di_node| {
319            // Fields that just belong to this variant/state
320            let state_specific_fields: SmallVec<_> = (0..variant_layout.fields.count())
321                .map(|field_index| {
322                    let coroutine_saved_local = coroutine_layout.variant_fields[variant_index]
323                        [FieldIdx::from_usize(field_index)];
324                    let field_name_maybe = coroutine_layout.field_names[coroutine_saved_local];
325                    let field_name = field_name_maybe
326                        .as_ref()
327                        .map(|s| Cow::from(s.as_str()))
328                        .unwrap_or_else(|| super::tuple_field_name(field_index));
329
330                    let field_type = variant_layout.field(cx, field_index).ty;
331
332                    build_field_di_node(
333                        cx,
334                        variant_struct_type_di_node,
335                        &field_name,
336                        cx.layout_of(field_type),
337                        variant_layout.fields.offset(field_index),
338                        DIFlags::FlagZero,
339                        type_di_node(cx, field_type),
340                        None,
341                    )
342                })
343                .collect();
344
345            // Fields that are common to all states
346            let common_fields: SmallVec<_> = coroutine_args
347                .prefix_tys()
348                .iter()
349                .zip(common_upvar_names)
350                .enumerate()
351                .map(|(index, (upvar_ty, upvar_name))| {
352                    build_field_di_node(
353                        cx,
354                        variant_struct_type_di_node,
355                        upvar_name.as_str(),
356                        cx.layout_of(upvar_ty),
357                        coroutine_type_and_layout.fields.offset(index),
358                        DIFlags::FlagZero,
359                        type_di_node(cx, upvar_ty),
360                        None,
361                    )
362                })
363                .collect();
364
365            state_specific_fields.into_iter().chain(common_fields).collect()
366        },
367        |cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
368    )
369    .di_node
370}
371
372#[derive(Copy, Clone)]
373enum DiscrResult {
374    NoDiscriminant,
375    Value(u128),
376    Range(u128, u128),
377}
378
379impl DiscrResult {
380    fn opt_single_val(&self) -> Option<u128> {
381        if let Self::Value(d) = *self { Some(d) } else { None }
382    }
383}
384
385/// Returns the discriminant value corresponding to the variant index.
386///
387/// Will return `None` if there is less than two variants (because then the enum won't have)
388/// a tag, and if this is the untagged variant of a niche-layout enum (because then there is no
389/// single discriminant value).
390fn compute_discriminant_value<'ll, 'tcx>(
391    cx: &CodegenCx<'ll, 'tcx>,
392    enum_type_and_layout: TyAndLayout<'tcx>,
393    variant_index: VariantIdx,
394) -> DiscrResult {
395    match enum_type_and_layout.layout.variants() {
396        &Variants::Single { .. } | &Variants::Empty => DiscrResult::NoDiscriminant,
397        &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value(
398            enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
399        ),
400        &Variants::Multiple {
401            tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, untagged_variant },
402            tag,
403            ..
404        } => {
405            if variant_index == untagged_variant {
406                let valid_range = enum_type_and_layout
407                    .for_variant(cx, variant_index)
408                    .largest_niche
409                    .as_ref()
410                    .unwrap()
411                    .valid_range;
412
413                let min = valid_range.start.min(valid_range.end);
414                let min = tag.size(cx).truncate(min);
415
416                let max = valid_range.start.max(valid_range.end);
417                let max = tag.size(cx).truncate(max);
418
419                DiscrResult::Range(min, max)
420            } else {
421                let value = (variant_index.as_u32() as u128)
422                    .wrapping_sub(niche_variants.start().as_u32() as u128)
423                    .wrapping_add(niche_start);
424                let value = tag.size(cx).truncate(value);
425                DiscrResult::Value(value)
426            }
427        }
428    }
429}