]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_codegen_llvm / src / debuginfo / metadata / enums / native.rs
CommitLineData
5e7ed085
FG
1use std::borrow::Cow;
2
3use crate::{
4 common::CodegenCx,
5 debuginfo::{
6 metadata::{
5e7ed085 7 enums::tag_base_type,
9c376795 8 file_metadata, size_and_align_of, type_di_node,
5e7ed085
FG
9 type_map::{self, Stub, StubInfo, UniqueTypeId},
10 unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS,
11 UNKNOWN_LINE_NUMBER,
12 },
13 utils::{create_DIArray, get_namespace_for_item, DIB},
14 },
15 llvm::{
16 self,
17 debuginfo::{DIFile, DIFlags, DIType},
18 },
19};
20use libc::c_uint;
21use rustc_codegen_ssa::{
22 debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo},
23 traits::ConstMethods,
24};
25use rustc_middle::{
26 bug,
27 ty::{
28 self,
29 layout::{LayoutOf, TyAndLayout},
30 },
31};
32use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants};
33use smallvec::smallvec;
34
35/// Build the debuginfo node for an enum type. The listing below shows how such a
36/// type looks like at the LLVM IR/DWARF level. It is a `DW_TAG_structure_type`
37/// with a single `DW_TAG_variant_part` that in turn contains a `DW_TAG_variant`
38/// for each variant of the enum. The variant-part also contains a single member
39/// describing the discriminant, and a nested struct type for each of the variants.
40///
41/// ```txt
42/// ---> DW_TAG_structure_type (top-level type for enum)
43/// DW_TAG_variant_part (variant part)
44/// DW_AT_discr (reference to discriminant DW_TAG_member)
45/// DW_TAG_member (discriminant member)
46/// DW_TAG_variant (variant 1)
47/// DW_TAG_variant (variant 2)
48/// DW_TAG_variant (variant 3)
49/// DW_TAG_structure_type (type of variant 1)
50/// DW_TAG_structure_type (type of variant 2)
51/// DW_TAG_structure_type (type of variant 3)
52/// ```
53pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
54 cx: &CodegenCx<'ll, 'tcx>,
55 unique_type_id: UniqueTypeId<'tcx>,
56) -> DINodeCreationResult<'ll> {
57 let enum_type = unique_type_id.expect_ty();
58 let &ty::Adt(enum_adt_def, _) = enum_type.kind() else {
59 bug!("build_enum_type_di_node() called with non-enum type: `{:?}`", enum_type)
60 };
61
62 let containing_scope = get_namespace_for_item(cx, enum_adt_def.did());
63 let enum_type_and_layout = cx.layout_of(enum_type);
64 let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
65
66 debug_assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
67
68 type_map::build_type_with_children(
69 cx,
70 type_map::stub(
71 cx,
72 Stub::Struct,
73 unique_type_id,
74 &enum_type_name,
75 size_and_align_of(enum_type_and_layout),
76 Some(containing_scope),
77 DIFlags::FlagZero,
78 ),
79 |cx, enum_type_di_node| {
80 // Build the struct type for each variant. These will be referenced by the
81 // DW_TAG_variant DIEs inside of the DW_TAG_variant_part DIE.
82 // We also called the names for the corresponding DW_TAG_variant DIEs here.
83 let variant_member_infos: SmallVec<_> = enum_adt_def
84 .variant_range()
85 .map(|variant_index| VariantMemberInfo {
86 variant_index,
87 variant_name: Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
88 variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node(
89 cx,
f2b60f7d 90 enum_type_and_layout,
5e7ed085
FG
91 enum_type_di_node,
92 variant_index,
93 enum_adt_def.variant(variant_index),
94 enum_type_and_layout.for_variant(cx, variant_index),
95 ),
96 source_info: None,
97 })
98 .collect();
99
100 smallvec![build_enum_variant_part_di_node(
101 cx,
102 enum_type_and_layout,
103 enum_type_di_node,
104 &variant_member_infos[..],
105 )]
106 },
107 // We don't seem to be emitting generic args on the enum type, it seems. Rather
108 // they get attached to the struct type of each variant.
109 NO_GENERICS,
110 )
111}
112
113/// Build the debuginfo node for a generator environment. It looks the same as the debuginfo for
114/// an enum. See [build_enum_type_di_node] for more information.
115///
116/// ```txt
117///
118/// ---> DW_TAG_structure_type (top-level type for the generator)
119/// DW_TAG_variant_part (variant part)
120/// DW_AT_discr (reference to discriminant DW_TAG_member)
121/// DW_TAG_member (discriminant member)
122/// DW_TAG_variant (variant 1)
123/// DW_TAG_variant (variant 2)
124/// DW_TAG_variant (variant 3)
125/// DW_TAG_structure_type (type of variant 1)
126/// DW_TAG_structure_type (type of variant 2)
127/// DW_TAG_structure_type (type of variant 3)
128///
129/// ```
130pub(super) fn build_generator_di_node<'ll, 'tcx>(
131 cx: &CodegenCx<'ll, 'tcx>,
132 unique_type_id: UniqueTypeId<'tcx>,
133) -> DINodeCreationResult<'ll> {
134 let generator_type = unique_type_id.expect_ty();
135 let &ty::Generator(generator_def_id, _, _ ) = generator_type.kind() else {
136 bug!("build_generator_di_node() called with non-generator type: `{:?}`", generator_type)
137 };
138
139 let containing_scope = get_namespace_for_item(cx, generator_def_id);
140 let generator_type_and_layout = cx.layout_of(generator_type);
141
142 debug_assert!(!wants_c_like_enum_debuginfo(generator_type_and_layout));
143
144 let generator_type_name = compute_debuginfo_type_name(cx.tcx, generator_type, false);
145
146 type_map::build_type_with_children(
147 cx,
148 type_map::stub(
149 cx,
150 Stub::Struct,
151 unique_type_id,
152 &generator_type_name,
153 size_and_align_of(generator_type_and_layout),
154 Some(containing_scope),
155 DIFlags::FlagZero,
156 ),
157 |cx, generator_type_di_node| {
158 let (generator_layout, state_specific_upvar_names) =
9c376795 159 cx.tcx.generator_layout_and_saved_local_names(generator_def_id);
5e7ed085
FG
160
161 let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } = generator_type_and_layout.variants else {
162 bug!(
163 "Encountered generator with non-direct-tag layout: {:?}",
164 generator_type_and_layout
165 )
166 };
167
168 let common_upvar_names =
9c376795 169 cx.tcx.closure_saved_names_of_captured_variables(generator_def_id);
5e7ed085
FG
170
171 // Build variant struct types
172 let variant_struct_type_di_nodes: SmallVec<_> = variants
173 .indices()
174 .map(|variant_index| {
175 // FIXME: This is problematic because just a number is not a valid identifier.
176 // GeneratorSubsts::variant_name(variant_index), would be consistent
177 // with enums?
178 let variant_name = format!("{}", variant_index.as_usize()).into();
179
180 let span = generator_layout.variant_source_info[variant_index].span;
181 let source_info = if !span.is_dummy() {
182 let loc = cx.lookup_debug_loc(span.lo());
183 Some((file_metadata(cx, &loc.file), loc.line))
184 } else {
185 None
186 };
187
188 VariantMemberInfo {
189 variant_index,
190 variant_name,
191 variant_struct_type_di_node:
192 super::build_generator_variant_struct_type_di_node(
193 cx,
194 variant_index,
195 generator_type_and_layout,
196 generator_type_di_node,
197 generator_layout,
198 &state_specific_upvar_names,
199 &common_upvar_names,
200 ),
201 source_info,
202 }
203 })
204 .collect();
205
206 smallvec![build_enum_variant_part_di_node(
207 cx,
208 generator_type_and_layout,
209 generator_type_di_node,
210 &variant_struct_type_di_nodes[..],
211 )]
212 },
213 // We don't seem to be emitting generic args on the generator type, it seems. Rather
214 // they get attached to the struct type of each variant.
215 NO_GENERICS,
216 )
217}
218
219/// Builds the DW_TAG_variant_part of an enum or generator debuginfo node:
220///
221/// ```txt
222/// DW_TAG_structure_type (top-level type for enum)
223/// ---> DW_TAG_variant_part (variant part)
224/// DW_AT_discr (reference to discriminant DW_TAG_member)
225/// DW_TAG_member (discriminant member)
226/// DW_TAG_variant (variant 1)
227/// DW_TAG_variant (variant 2)
228/// DW_TAG_variant (variant 3)
229/// DW_TAG_structure_type (type of variant 1)
230/// DW_TAG_structure_type (type of variant 2)
231/// DW_TAG_structure_type (type of variant 3)
232/// ```
233fn build_enum_variant_part_di_node<'ll, 'tcx>(
234 cx: &CodegenCx<'ll, 'tcx>,
235 enum_type_and_layout: TyAndLayout<'tcx>,
236 enum_type_di_node: &'ll DIType,
237 variant_member_infos: &[VariantMemberInfo<'_, 'll>],
238) -> &'ll DIType {
239 let tag_member_di_node =
240 build_discr_member_di_node(cx, enum_type_and_layout, enum_type_di_node);
241
242 let variant_part_unique_type_id =
243 UniqueTypeId::for_enum_variant_part(cx.tcx, enum_type_and_layout.ty);
244
245 let stub = StubInfo::new(
246 cx,
247 variant_part_unique_type_id,
248 |cx, variant_part_unique_type_id_str| unsafe {
249 let variant_part_name = "";
250 llvm::LLVMRustDIBuilderCreateVariantPart(
251 DIB(cx),
252 enum_type_di_node,
253 variant_part_name.as_ptr().cast(),
254 variant_part_name.len(),
255 unknown_file_metadata(cx),
256 UNKNOWN_LINE_NUMBER,
257 enum_type_and_layout.size.bits(),
258 enum_type_and_layout.align.abi.bits() as u32,
259 DIFlags::FlagZero,
260 tag_member_di_node,
261 create_DIArray(DIB(cx), &[]),
262 variant_part_unique_type_id_str.as_ptr().cast(),
263 variant_part_unique_type_id_str.len(),
264 )
265 },
266 );
267
268 type_map::build_type_with_children(
269 cx,
270 stub,
271 |cx, variant_part_di_node| {
272 variant_member_infos
273 .iter()
274 .map(|variant_member_info| {
275 build_enum_variant_member_di_node(
276 cx,
277 enum_type_and_layout,
278 variant_part_di_node,
279 variant_member_info,
280 )
281 })
282 .collect()
283 },
284 NO_GENERICS,
285 )
286 .di_node
287}
288
289/// Builds the DW_TAG_member describing where we can find the tag of an enum.
290/// Returns `None` if the enum does not have a tag.
291///
292/// ```txt
293///
294/// DW_TAG_structure_type (top-level type for enum)
295/// DW_TAG_variant_part (variant part)
296/// DW_AT_discr (reference to discriminant DW_TAG_member)
297/// ---> DW_TAG_member (discriminant member)
298/// DW_TAG_variant (variant 1)
299/// DW_TAG_variant (variant 2)
300/// DW_TAG_variant (variant 3)
301/// DW_TAG_structure_type (type of variant 1)
302/// DW_TAG_structure_type (type of variant 2)
303/// DW_TAG_structure_type (type of variant 3)
304///
305/// ```
306fn build_discr_member_di_node<'ll, 'tcx>(
307 cx: &CodegenCx<'ll, 'tcx>,
308 enum_or_generator_type_and_layout: TyAndLayout<'tcx>,
309 enum_or_generator_type_di_node: &'ll DIType,
310) -> Option<&'ll DIType> {
311 let tag_name = match enum_or_generator_type_and_layout.ty.kind() {
312 ty::Generator(..) => "__state",
313 _ => "",
314 };
315
316 // NOTE: This is actually wrong. This will become a member of
317 // of the DW_TAG_variant_part. But, due to LLVM's API, that
318 // can only be constructed with this DW_TAG_member already in created.
319 // In LLVM IR the wrong scope will be listed but when DWARF is
320 // generated from it, the DW_TAG_member will be a child the
321 // DW_TAG_variant_part.
322 let containing_scope = enum_or_generator_type_di_node;
323
324 match enum_or_generator_type_and_layout.layout.variants() {
325 // A single-variant enum has no discriminant.
326 &Variants::Single { .. } => None,
327
328 &Variants::Multiple { tag_field, .. } => {
329 let tag_base_type = tag_base_type(cx, enum_or_generator_type_and_layout);
330 let (size, align) = cx.size_and_align_of(tag_base_type);
331
332 unsafe {
333 Some(llvm::LLVMRustDIBuilderCreateMemberType(
334 DIB(cx),
335 containing_scope,
336 tag_name.as_ptr().cast(),
337 tag_name.len(),
338 unknown_file_metadata(cx),
339 UNKNOWN_LINE_NUMBER,
340 size.bits(),
341 align.bits() as u32,
342 enum_or_generator_type_and_layout.fields.offset(tag_field).bits(),
343 DIFlags::FlagArtificial,
344 type_di_node(cx, tag_base_type),
345 ))
346 }
347 }
348 }
349}
350
351/// Build the debuginfo node for `DW_TAG_variant`:
352///
353/// ```txt
354/// DW_TAG_structure_type (top-level type for enum)
355/// DW_TAG_variant_part (variant part)
356/// DW_AT_discr (reference to discriminant DW_TAG_member)
357/// DW_TAG_member (discriminant member)
358/// ---> DW_TAG_variant (variant 1)
359/// ---> DW_TAG_variant (variant 2)
360/// ---> DW_TAG_variant (variant 3)
361/// DW_TAG_structure_type (type of variant 1)
362/// DW_TAG_structure_type (type of variant 2)
363/// DW_TAG_structure_type (type of variant 3)
364/// ```
365///
366/// This node looks like:
367///
368/// ```txt
369/// DW_TAG_variant
370/// DW_AT_discr_value 0
371/// DW_TAG_member
372/// DW_AT_name None
373/// DW_AT_type <0x000002a1>
374/// DW_AT_alignment 0x00000002
375/// DW_AT_data_member_location 0
376/// ```
377///
378/// The DW_AT_discr_value is optional, and is omitted if
379/// - This is the only variant of a univariant enum (i.e. their is no discriminant)
f2b60f7d 380/// - This is the "untagged" variant of a niche-layout enum
5e7ed085
FG
381/// (where only the other variants are identified by a single value)
382///
383/// There is only ever a single member, the type of which is a struct that describes the
384/// fields of the variant (excluding the discriminant). The name of the member is the name
385/// of the variant as given in the source code. The DW_AT_data_member_location is always
386/// zero.
387///
388/// Note that the LLVM DIBuilder API is a bit unintuitive here. The DW_TAG_variant subtree
389/// (including the DW_TAG_member) is built by a single call to
390/// `LLVMRustDIBuilderCreateVariantMemberType()`.
391fn build_enum_variant_member_di_node<'ll, 'tcx>(
392 cx: &CodegenCx<'ll, 'tcx>,
393 enum_type_and_layout: TyAndLayout<'tcx>,
394 variant_part_di_node: &'ll DIType,
395 variant_member_info: &VariantMemberInfo<'_, 'll>,
396) -> &'ll DIType {
397 let variant_index = variant_member_info.variant_index;
398 let discr_value = super::compute_discriminant_value(cx, enum_type_and_layout, variant_index);
399
400 let (file_di_node, line_number) = variant_member_info
401 .source_info
402 .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
403
404 unsafe {
405 llvm::LLVMRustDIBuilderCreateVariantMemberType(
406 DIB(cx),
407 variant_part_di_node,
408 variant_member_info.variant_name.as_ptr().cast(),
409 variant_member_info.variant_name.len(),
410 file_di_node,
411 line_number,
412 enum_type_and_layout.size.bits(),
413 enum_type_and_layout.align.abi.bits() as u32,
414 Size::ZERO.bits(),
f2b60f7d
FG
415 discr_value.opt_single_val().map(|value| {
416 // NOTE(eddyb) do *NOT* remove this assert, until
417 // we pass the full 128-bit value to LLVM, otherwise
418 // truncation will be silent and remain undetected.
419 assert_eq!(value as u64 as u128, value);
420 cx.const_u64(value as u64)
421 }),
5e7ed085
FG
422 DIFlags::FlagZero,
423 variant_member_info.variant_struct_type_di_node,
424 )
425 }
426}
427
428/// Information needed for building a `DW_TAG_variant`:
429///
430/// ```txt
431/// DW_TAG_structure_type (top-level type for enum)
432/// DW_TAG_variant_part (variant part)
433/// DW_AT_discr (reference to discriminant DW_TAG_member)
434/// DW_TAG_member (discriminant member)
435/// ---> DW_TAG_variant (variant 1)
436/// ---> DW_TAG_variant (variant 2)
437/// ---> DW_TAG_variant (variant 3)
438/// DW_TAG_structure_type (type of variant 1)
439/// DW_TAG_structure_type (type of variant 2)
440/// DW_TAG_structure_type (type of variant 3)
441struct VariantMemberInfo<'a, 'll> {
442 variant_index: VariantIdx,
443 variant_name: Cow<'a, str>,
444 variant_struct_type_di_node: &'ll DIType,
445 source_info: Option<(&'ll DIFile, c_uint)>,
446}