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