rustc_codegen_llvm/debuginfo/metadata/enums/
native.rs1use std::borrow::Cow;
2
3use libc::c_uint;
4use rustc_abi::{Size, TagEncoding, VariantIdx, Variants};
5use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
6use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
7use rustc_codegen_ssa::traits::{ConstCodegenMethods, MiscCodegenMethods};
8use rustc_middle::bug;
9use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
10use rustc_middle::ty::{self};
11use smallvec::smallvec;
12
13use crate::common::{AsCCharPtr, CodegenCx};
14use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
15use crate::debuginfo::metadata::{
16 DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, create_member_type,
17 file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
18 unknown_file_metadata, visibility_di_flags,
19};
20use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
21use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
22use crate::llvm::{self};
23
24pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
43 cx: &CodegenCx<'ll, 'tcx>,
44 unique_type_id: UniqueTypeId<'tcx>,
45) -> DINodeCreationResult<'ll> {
46 let enum_type = unique_type_id.expect_ty();
47 let &ty::Adt(enum_adt_def, _) = enum_type.kind() else {
48 ::rustc_middle::util::bug::bug_fmt(format_args!("build_enum_type_di_node() called with non-enum type: `{0:?}`",
enum_type))bug!("build_enum_type_di_node() called with non-enum type: `{:?}`", enum_type)
49 };
50
51 let containing_scope = get_namespace_for_item(cx, enum_adt_def.did());
52 let enum_type_and_layout = cx.layout_of(enum_type);
53 let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
54
55 let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
56
57 if !!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout) {
::core::panicking::panic("assertion failed: !wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout)")
};assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
58
59 let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
60 Some(file_metadata_from_def_id(cx, Some(enum_adt_def.did())))
61 } else {
62 None
63 };
64
65 type_map::build_type_with_children(
66 cx,
67 type_map::stub(
68 cx,
69 Stub::Struct,
70 unique_type_id,
71 &enum_type_name,
72 def_location,
73 size_and_align_of(enum_type_and_layout),
74 Some(containing_scope),
75 visibility_flags,
76 ),
77 |cx, enum_type_di_node| {
78 let variant_member_infos: SmallVec<_> = enum_adt_def
82 .variant_range()
83 .map(|variant_index| VariantMemberInfo {
84 variant_index,
85 variant_name: Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
86 variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node(
87 cx,
88 enum_type_and_layout,
89 enum_type_di_node,
90 variant_index,
91 enum_adt_def.variant(variant_index),
92 enum_type_and_layout.for_variant(cx, variant_index),
93 visibility_flags,
94 ),
95 source_info: if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
96 Some(file_metadata_from_def_id(
97 cx,
98 Some(enum_adt_def.variant(variant_index).def_id),
99 ))
100 } else {
101 None
102 },
103 })
104 .collect();
105
106 let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
107 Some(enum_adt_def.did())
108 } else {
109 None
110 };
111 {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(build_enum_variant_part_di_node(cx, enum_type_and_layout,
enum_type_di_node, enum_adt_def_id,
&variant_member_infos[..]));
vec
} else {
::smallvec::SmallVec::from_vec(<[_]>::into_vec(::alloc::boxed::box_new([build_enum_variant_part_di_node(cx,
enum_type_and_layout, enum_type_di_node, enum_adt_def_id,
&variant_member_infos[..])])))
}
}smallvec![build_enum_variant_part_di_node(
112 cx,
113 enum_type_and_layout,
114 enum_type_di_node,
115 enum_adt_def_id,
116 &variant_member_infos[..],
117 )]
118 },
119 NO_GENERICS,
122 )
123}
124
125pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
143 cx: &CodegenCx<'ll, 'tcx>,
144 unique_type_id: UniqueTypeId<'tcx>,
145) -> DINodeCreationResult<'ll> {
146 let coroutine_type = unique_type_id.expect_ty();
147 let &ty::Coroutine(coroutine_def_id, coroutine_args) = coroutine_type.kind() else {
148 ::rustc_middle::util::bug::bug_fmt(format_args!("build_coroutine_di_node() called with non-coroutine type: `{0:?}`",
coroutine_type))bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type)
149 };
150
151 let containing_scope = get_namespace_for_item(cx, coroutine_def_id);
152 let coroutine_type_and_layout = cx.layout_of(coroutine_type);
153
154 if !!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout) {
::core::panicking::panic("assertion failed: !wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout)")
};assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));
155
156 let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
157
158 let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
159 Some(file_metadata_from_def_id(cx, Some(coroutine_def_id)))
160 } else {
161 None
162 };
163
164 type_map::build_type_with_children(
165 cx,
166 type_map::stub(
167 cx,
168 Stub::Struct,
169 unique_type_id,
170 &coroutine_type_name,
171 def_location,
172 size_and_align_of(coroutine_type_and_layout),
173 Some(containing_scope),
174 DIFlags::FlagZero,
175 ),
176 |cx, coroutine_type_di_node| {
177 let coroutine_layout =
178 cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args).unwrap();
179
180 let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } =
181 coroutine_type_and_layout.variants
182 else {
183 ::rustc_middle::util::bug::bug_fmt(format_args!("Encountered coroutine with non-direct-tag layout: {0:?}",
coroutine_type_and_layout))bug!(
184 "Encountered coroutine with non-direct-tag layout: {:?}",
185 coroutine_type_and_layout
186 )
187 };
188
189 let common_upvar_names =
190 cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id);
191
192 let variant_struct_type_di_nodes: SmallVec<_> = variants
194 .indices()
195 .map(|variant_index| {
196 let variant_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", variant_index.as_usize()))
})format!("{}", variant_index.as_usize()).into();
200
201 let span = coroutine_layout.variant_source_info[variant_index].span;
202 let source_info = if !span.is_dummy() {
203 let loc = cx.lookup_debug_loc(span.lo());
204 Some((file_metadata(cx, &loc.file), loc.line))
205 } else {
206 None
207 };
208
209 VariantMemberInfo {
210 variant_index,
211 variant_name,
212 variant_struct_type_di_node:
213 super::build_coroutine_variant_struct_type_di_node(
214 cx,
215 variant_index,
216 coroutine_type_and_layout,
217 coroutine_type_di_node,
218 coroutine_layout,
219 common_upvar_names,
220 ),
221 source_info,
222 }
223 })
224 .collect();
225
226 let coroutine_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
227 Some(coroutine_def_id)
228 } else {
229 None
230 };
231 {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(build_enum_variant_part_di_node(cx,
coroutine_type_and_layout, coroutine_type_di_node,
coroutine_def_id, &variant_struct_type_di_nodes[..]));
vec
} else {
::smallvec::SmallVec::from_vec(<[_]>::into_vec(::alloc::boxed::box_new([build_enum_variant_part_di_node(cx,
coroutine_type_and_layout, coroutine_type_di_node,
coroutine_def_id, &variant_struct_type_di_nodes[..])])))
}
}smallvec![build_enum_variant_part_di_node(
232 cx,
233 coroutine_type_and_layout,
234 coroutine_type_di_node,
235 coroutine_def_id,
236 &variant_struct_type_di_nodes[..],
237 )]
238 },
239 NO_GENERICS,
242 )
243}
244
245fn build_enum_variant_part_di_node<'ll, 'tcx>(
260 cx: &CodegenCx<'ll, 'tcx>,
261 enum_type_and_layout: TyAndLayout<'tcx>,
262 enum_type_di_node: &'ll DIType,
263 enum_type_def_id: Option<rustc_span::def_id::DefId>,
264 variant_member_infos: &[VariantMemberInfo<'_, 'll>],
265) -> &'ll DIType {
266 let tag_member_di_node =
267 build_discr_member_di_node(cx, enum_type_and_layout, enum_type_di_node);
268
269 let variant_part_unique_type_id =
270 UniqueTypeId::for_enum_variant_part(cx.tcx, enum_type_and_layout.ty);
271
272 let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
273 {
274 file_metadata_from_def_id(cx, enum_type_def_id)
275 } else {
276 (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
277 };
278
279 let stub = StubInfo::new(
280 cx,
281 variant_part_unique_type_id,
282 |cx, variant_part_unique_type_id_str| unsafe {
283 let variant_part_name = "";
284 llvm::LLVMRustDIBuilderCreateVariantPart(
285 DIB(cx),
286 enum_type_di_node,
287 variant_part_name.as_c_char_ptr(),
288 variant_part_name.len(),
289 file_metadata,
290 line_number,
291 enum_type_and_layout.size.bits(),
292 enum_type_and_layout.align.bits() as u32,
293 DIFlags::FlagZero,
294 tag_member_di_node,
295 create_DIArray(DIB(cx), &[]),
296 variant_part_unique_type_id_str.as_c_char_ptr(),
297 variant_part_unique_type_id_str.len(),
298 )
299 },
300 );
301
302 type_map::build_type_with_children(
303 cx,
304 stub,
305 |cx, variant_part_di_node| {
306 variant_member_infos
307 .iter()
308 .map(|variant_member_info| {
309 build_enum_variant_member_di_node(
310 cx,
311 enum_type_and_layout,
312 variant_part_di_node,
313 variant_member_info,
314 )
315 })
316 .collect()
317 },
318 NO_GENERICS,
319 )
320 .di_node
321}
322
323fn build_discr_member_di_node<'ll, 'tcx>(
341 cx: &CodegenCx<'ll, 'tcx>,
342 enum_or_coroutine_type_and_layout: TyAndLayout<'tcx>,
343 enum_or_coroutine_type_di_node: &'ll DIType,
344) -> Option<&'ll DIType> {
345 let tag_name = match enum_or_coroutine_type_and_layout.ty.kind() {
346 ty::Coroutine(..) => "__state",
347 _ => "",
348 };
349
350 let containing_scope = enum_or_coroutine_type_di_node;
357
358 match enum_or_coroutine_type_and_layout.layout.variants() {
359 &Variants::Single { .. } | &Variants::Empty => None,
361
362 &Variants::Multiple { tag_field, .. } => {
363 let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
364 let ty = type_di_node(cx, tag_base_type);
365 let file = unknown_file_metadata(cx);
366
367 let layout = cx.layout_of(tag_base_type);
368
369 Some(create_member_type(
370 cx,
371 containing_scope,
372 &tag_name,
373 file,
374 UNKNOWN_LINE_NUMBER,
375 layout,
376 enum_or_coroutine_type_and_layout.fields.offset(tag_field.as_usize()),
377 DIFlags::FlagArtificial,
378 ty,
379 ))
380 }
381 }
382}
383
384fn build_enum_variant_member_di_node<'ll, 'tcx>(
425 cx: &CodegenCx<'ll, 'tcx>,
426 enum_type_and_layout: TyAndLayout<'tcx>,
427 variant_part_di_node: &'ll DIType,
428 variant_member_info: &VariantMemberInfo<'_, 'll>,
429) -> &'ll DIType {
430 let variant_index = variant_member_info.variant_index;
431 let discr_value = super::compute_discriminant_value(cx, enum_type_and_layout, variant_index);
432
433 let (file_di_node, line_number) = variant_member_info
434 .source_info
435 .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
436
437 let discr = discr_value.opt_single_val().map(|value| {
438 let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
439 let size = cx.size_of(tag_base_type);
440 cx.const_uint_big(cx.type_ix(size.bits()), value)
441 });
442
443 unsafe {
444 llvm::LLVMRustDIBuilderCreateVariantMemberType(
445 DIB(cx),
446 variant_part_di_node,
447 variant_member_info.variant_name.as_c_char_ptr(),
448 variant_member_info.variant_name.len(),
449 file_di_node,
450 line_number,
451 enum_type_and_layout.size.bits(),
452 enum_type_and_layout.align.bits() as u32,
453 Size::ZERO.bits(),
454 discr,
455 DIFlags::FlagZero,
456 variant_member_info.variant_struct_type_di_node,
457 )
458 }
459}
460
461struct VariantMemberInfo<'a, 'll> {
476 variant_index: VariantIdx,
477 variant_name: Cow<'a, str>,
478 variant_struct_type_di_node: &'ll DIType,
479 source_info: Option<(&'ll DIFile, c_uint)>,
480}