]>
Commit | Line | Data |
---|---|---|
5e7ed085 FG |
1 | use std::borrow::Cow; |
2 | ||
3 | use 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 | }; | |
20 | use libc::c_uint; | |
21 | use rustc_codegen_ssa::{ | |
22 | debuginfo::{type_names::compute_debuginfo_type_name, wants_c_like_enum_debuginfo}, | |
23 | traits::ConstMethods, | |
24 | }; | |
25 | use rustc_middle::{ | |
26 | bug, | |
27 | ty::{ | |
28 | self, | |
29 | layout::{LayoutOf, TyAndLayout}, | |
30 | }, | |
31 | }; | |
32 | use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants}; | |
33 | use 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 | /// ``` | |
53 | pub(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 | /// ``` | |
130 | pub(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 | /// ``` | |
233 | fn 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 | /// ``` | |
306 | fn 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()`. | |
391 | fn 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) | |
353b0b11 | 441 | /// ``` |
5e7ed085 FG |
442 | struct VariantMemberInfo<'a, 'll> { |
443 | variant_index: VariantIdx, | |
444 | variant_name: Cow<'a, str>, | |
445 | variant_struct_type_di_node: &'ll DIType, | |
446 | source_info: Option<(&'ll DIFile, c_uint)>, | |
447 | } |