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