2022-03-03 10:15:25 +00:00
|
|
|
use std::borrow::Cow;
|
2021-10-06 12:26:50 +00:00
|
|
|
use std::fmt::{self, Write};
|
2019-12-24 22:38:22 +00:00
|
|
|
use std::hash::{Hash, Hasher};
|
2020-02-25 00:00:00 +00:00
|
|
|
use std::path::{Path, PathBuf};
|
2022-03-03 10:15:25 +00:00
|
|
|
use std::{iter, ptr};
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-04-21 13:02:54 +00:00
|
|
|
use libc::{c_char, c_longlong, c_uint};
|
2024-11-03 02:32:52 +00:00
|
|
|
use rustc_abi::{Align, Size};
|
2021-12-28 21:57:18 +00:00
|
|
|
use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo};
|
2019-12-24 22:38:22 +00:00
|
|
|
use rustc_codegen_ssa::traits::*;
|
2020-01-05 01:37:57 +00:00
|
|
|
use rustc_hir::def::{CtorKind, DefKind};
|
2020-02-10 01:03:24 +00:00
|
|
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
2022-01-10 14:59:52 +00:00
|
|
|
use rustc_middle::bug;
|
2024-11-15 12:53:31 +00:00
|
|
|
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout};
|
2022-04-21 13:02:54 +00:00
|
|
|
use rustc_middle::ty::{
|
2024-11-15 12:53:31 +00:00
|
|
|
self, AdtKind, CoroutineArgsExt, Instance, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
|
2022-04-21 13:02:54 +00:00
|
|
|
};
|
|
|
|
use rustc_session::config::{self, DebugInfo, Lto};
|
2024-12-12 23:29:23 +00:00
|
|
|
use rustc_span::{DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Symbol, hygiene};
|
2022-04-21 13:02:54 +00:00
|
|
|
use rustc_symbol_mangling::typeid_for_trait_ref;
|
2023-12-11 21:24:24 +00:00
|
|
|
use rustc_target::spec::DebuginfoKind;
|
2022-03-03 10:15:25 +00:00
|
|
|
use smallvec::smallvec;
|
2024-05-22 04:50:24 +00:00
|
|
|
use tracing::{debug, instrument};
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2025-01-05 00:38:43 +00:00
|
|
|
pub(crate) use self::type_map::TypeMap;
|
2022-04-21 13:02:54 +00:00
|
|
|
use self::type_map::{DINodeCreationResult, Stub, UniqueTypeId};
|
2018-07-26 15:11:10 +00:00
|
|
|
use super::CodegenUnitDebugContext;
|
2022-04-21 13:02:54 +00:00
|
|
|
use super::namespace::mangled_name_of_instance;
|
|
|
|
use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name};
|
2022-01-13 17:13:54 +00:00
|
|
|
use super::utils::{
|
2022-04-21 13:02:54 +00:00
|
|
|
DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit,
|
2018-07-04 13:36:49 +00:00
|
|
|
};
|
2024-10-28 07:52:39 +00:00
|
|
|
use crate::common::{AsCCharPtr, CodegenCx};
|
2025-01-05 00:38:43 +00:00
|
|
|
use crate::debuginfo::dwarf_const;
|
2017-12-14 07:09:19 +00:00
|
|
|
use crate::debuginfo::metadata::type_map::build_type_with_children;
|
2024-10-03 13:05:23 +00:00
|
|
|
use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
|
2019-12-24 22:38:22 +00:00
|
|
|
use crate::llvm::debuginfo::{
|
|
|
|
DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
|
2023-11-16 04:07:37 +00:00
|
|
|
DebugNameTableKind,
|
2024-07-28 22:13:50 +00:00
|
|
|
};
|
2019-12-24 22:38:22 +00:00
|
|
|
use crate::value::Value;
|
|
|
|
use crate::{abi, llvm};
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2018-07-04 13:36:49 +00:00
|
|
|
impl PartialEq for llvm::Metadata {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2019-01-12 15:13:33 +00:00
|
|
|
ptr::eq(self, other)
|
2018-07-04 13:36:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for llvm::Metadata {}
|
|
|
|
|
|
|
|
impl Hash for llvm::Metadata {
|
|
|
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
|
|
|
(self as *const Self).hash(hasher);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for llvm::Metadata {
|
2019-02-25 07:40:18 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2018-07-04 13:36:49 +00:00
|
|
|
(self as *const Self).fmt(f)
|
|
|
|
}
|
|
|
|
}
|
2016-10-21 21:56:36 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
pub(super) const UNKNOWN_LINE_NUMBER: c_uint = 0;
|
|
|
|
pub(super) const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
|
2022-02-04 12:19:55 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
const NO_SCOPE_METADATA: Option<&DIScope> = None;
|
|
|
|
/// A function that returns an empty list of generic parameter debuginfo nodes.
|
|
|
|
const NO_GENERICS: for<'ll> fn(&CodegenCx<'ll, '_>) -> SmallVec<&'ll DIType> = |_| SmallVec::new();
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
// SmallVec is used quite a bit in this module, so create a shorthand.
|
|
|
|
// The actual number of elements is not so important.
|
2024-07-06 12:26:42 +00:00
|
|
|
type SmallVec<T> = smallvec::SmallVec<[T; 16]>;
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
mod enums;
|
|
|
|
mod type_map;
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Returns from the enclosing function if the type debuginfo node with the given
|
2019-05-17 01:20:14 +00:00
|
|
|
/// unique ID can be found in the type map.
|
2022-03-03 10:15:25 +00:00
|
|
|
macro_rules! return_if_di_node_created_in_meantime {
|
2019-12-24 22:38:22 +00:00
|
|
|
($cx: expr, $unique_type_id: expr) => {
|
2022-03-03 10:15:25 +00:00
|
|
|
if let Some(di_node) = debug_context($cx).type_map.di_node_for_unique_id($unique_type_id) {
|
|
|
|
return DINodeCreationResult::new(di_node, true);
|
2015-10-21 16:20:46 +00:00
|
|
|
}
|
2019-12-24 22:38:22 +00:00
|
|
|
};
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Extract size and alignment from a TyAndLayout.
|
2022-06-20 15:50:27 +00:00
|
|
|
#[inline]
|
2022-12-20 21:10:40 +00:00
|
|
|
fn size_and_align_of(ty_and_layout: TyAndLayout<'_>) -> (Size, Align) {
|
2022-03-03 10:15:25 +00:00
|
|
|
(ty_and_layout.size, ty_and_layout.align.abi)
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:13:54 +00:00
|
|
|
/// Creates debuginfo for a fixed size array (e.g. `[u64; 123]`).
|
2022-03-03 10:15:25 +00:00
|
|
|
/// For slices (that is, "arrays" of unknown size) use [build_slice_type_di_node].
|
|
|
|
fn build_fixed_size_array_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-01-13 17:13:54 +00:00
|
|
|
array_type: Ty<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-01-13 17:13:54 +00:00
|
|
|
let ty::Array(element_type, len) = array_type.kind() else {
|
2022-03-03 10:15:25 +00:00
|
|
|
bug!("build_fixed_size_array_di_node() called with non-ty::Array type `{:?}`", array_type)
|
2022-01-13 17:13:54 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let element_type_di_node = type_di_node(cx, *element_type);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
return_if_di_node_created_in_meantime!(cx, unique_type_id);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-01-13 17:13:54 +00:00
|
|
|
let (size, align) = cx.size_and_align_of(array_type);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2024-09-21 00:38:11 +00:00
|
|
|
let upper_bound = len
|
|
|
|
.try_to_target_usize(cx.tcx)
|
|
|
|
.expect("expected monomorphic const in codegen") as c_longlong;
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
let subrange =
|
|
|
|
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
|
2015-04-24 04:48:10 +00:00
|
|
|
|
|
|
|
let subscripts = create_DIArray(DIB(cx), &[subrange]);
|
2022-03-03 10:15:25 +00:00
|
|
|
let di_node = unsafe {
|
2016-08-01 23:35:09 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateArrayType(
|
2015-04-24 04:48:10 +00:00
|
|
|
DIB(cx),
|
2017-06-01 18:50:53 +00:00
|
|
|
size.bits(),
|
2018-09-08 22:16:45 +00:00
|
|
|
align.bits() as u32,
|
2022-03-03 10:15:25 +00:00
|
|
|
element_type_di_node,
|
2019-12-24 22:38:22 +00:00
|
|
|
subscripts,
|
|
|
|
)
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
DINodeCreationResult::new(di_node, false)
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 17:13:54 +00:00
|
|
|
/// Creates debuginfo for built-in pointer-like things:
|
|
|
|
///
|
|
|
|
/// - ty::Ref
|
|
|
|
/// - ty::RawPtr
|
|
|
|
/// - ty::Adt in the case it's Box
|
|
|
|
///
|
|
|
|
/// At some point we might want to remove the special handling of Box
|
|
|
|
/// and treat it the same as other smart pointers (like Rc, Arc, ...).
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-01-13 17:13:54 +00:00
|
|
|
ptr_type: Ty<'tcx>,
|
|
|
|
pointee_type: Ty<'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-03-24 09:59:28 +00:00
|
|
|
// The debuginfo generated by this function is only valid if `ptr_type` is really just
|
2024-10-03 13:05:23 +00:00
|
|
|
// a (wide) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
|
2024-07-19 23:52:33 +00:00
|
|
|
assert_eq!(
|
2022-03-24 09:59:28 +00:00
|
|
|
cx.size_and_align_of(ptr_type),
|
2023-07-05 19:13:26 +00:00
|
|
|
cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
|
2022-03-24 09:59:28 +00:00
|
|
|
);
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let pointee_type_di_node = type_di_node(cx, pointee_type);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
return_if_di_node_created_in_meantime!(cx, unique_type_id);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2023-03-26 16:55:37 +00:00
|
|
|
let data_layout = &cx.tcx.data_layout;
|
2022-01-13 17:13:54 +00:00
|
|
|
let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2024-10-03 13:05:23 +00:00
|
|
|
match wide_pointer_kind(cx, pointee_type) {
|
2022-01-13 17:13:54 +00:00
|
|
|
None => {
|
|
|
|
// This is a thin pointer. Create a regular pointer type and give it the correct name.
|
2024-07-19 23:52:33 +00:00
|
|
|
assert_eq!(
|
2023-03-26 16:55:37 +00:00
|
|
|
(data_layout.pointer_size, data_layout.pointer_align.abi),
|
2022-02-23 16:11:50 +00:00
|
|
|
cx.size_and_align_of(ptr_type),
|
2023-07-25 21:04:01 +00:00
|
|
|
"ptr_type={ptr_type}, pointee_type={pointee_type}",
|
2022-01-13 17:13:54 +00:00
|
|
|
);
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let di_node = unsafe {
|
2022-01-13 17:13:54 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreatePointerType(
|
|
|
|
DIB(cx),
|
2022-03-03 10:15:25 +00:00
|
|
|
pointee_type_di_node,
|
2023-03-26 16:55:37 +00:00
|
|
|
data_layout.pointer_size.bits(),
|
|
|
|
data_layout.pointer_align.abi.bits() as u32,
|
2022-01-13 17:13:54 +00:00
|
|
|
0, // Ignore DWARF address space.
|
2024-10-28 07:52:39 +00:00
|
|
|
ptr_type_debuginfo_name.as_c_char_ptr(),
|
2022-01-13 17:13:54 +00:00
|
|
|
ptr_type_debuginfo_name.len(),
|
|
|
|
)
|
2022-03-03 10:15:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
DINodeCreationResult { di_node, already_stored_in_typemap: false }
|
2022-01-13 17:13:54 +00:00
|
|
|
}
|
2024-10-03 13:05:23 +00:00
|
|
|
Some(wide_pointer_kind) => {
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
|
|
|
cx,
|
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&ptr_type_debuginfo_name,
|
2022-11-17 02:31:30 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
cx.size_and_align_of(ptr_type),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
|cx, owner| {
|
2024-10-03 13:05:23 +00:00
|
|
|
// FIXME: If this wide pointer is a `Box` then we don't want to use its
|
2022-03-24 09:59:28 +00:00
|
|
|
// type layout and instead use the layout of the raw pointer inside
|
|
|
|
// of it.
|
|
|
|
// The proper way to handle this is to not treat Box as a pointer
|
|
|
|
// at all and instead emit regular struct debuginfo for it. We just
|
|
|
|
// need to make sure that we don't break existing debuginfo consumers
|
|
|
|
// by doing that (at least not without a warning period).
|
2023-07-05 19:13:26 +00:00
|
|
|
let layout_type = if ptr_type.is_box() {
|
2024-09-18 03:34:49 +00:00
|
|
|
// The assertion at the start of this function ensures we have a ZST
|
|
|
|
// allocator. We'll make debuginfo "skip" all ZST allocators, not just the
|
|
|
|
// default allocator.
|
2023-07-05 19:13:26 +00:00
|
|
|
Ty::new_mut_ptr(cx.tcx, pointee_type)
|
|
|
|
} else {
|
|
|
|
ptr_type
|
|
|
|
};
|
2022-03-24 09:59:28 +00:00
|
|
|
|
|
|
|
let layout = cx.layout_of(layout_type);
|
2024-10-03 13:05:23 +00:00
|
|
|
let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR);
|
|
|
|
let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA);
|
2022-03-03 10:15:25 +00:00
|
|
|
|
2024-10-03 13:05:23 +00:00
|
|
|
let (addr_field_name, extra_field_name) = match wide_pointer_kind {
|
|
|
|
WidePtrKind::Dyn => ("pointer", "vtable"),
|
|
|
|
WidePtrKind::Slice => ("data_ptr", "length"),
|
2022-03-03 10:15:25 +00:00
|
|
|
};
|
2022-01-13 17:13:54 +00:00
|
|
|
|
2024-10-03 13:05:23 +00:00
|
|
|
assert_eq!(abi::WIDE_PTR_ADDR, 0);
|
|
|
|
assert_eq!(abi::WIDE_PTR_EXTRA, 1);
|
2022-01-13 17:13:54 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
// The data pointer type is a regular, thin pointer, regardless of whether this
|
|
|
|
// is a slice or a trait object.
|
|
|
|
let data_ptr_type_di_node = unsafe {
|
|
|
|
llvm::LLVMRustDIBuilderCreatePointerType(
|
|
|
|
DIB(cx),
|
|
|
|
pointee_type_di_node,
|
|
|
|
addr_field.size.bits(),
|
|
|
|
addr_field.align.abi.bits() as u32,
|
|
|
|
0, // Ignore DWARF address space.
|
|
|
|
std::ptr::null(),
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
};
|
2022-01-13 17:13:54 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
smallvec![
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
|
|
|
owner,
|
|
|
|
addr_field_name,
|
|
|
|
(addr_field.size, addr_field.align.abi),
|
2024-10-03 13:05:23 +00:00
|
|
|
layout.fields.offset(abi::WIDE_PTR_ADDR),
|
2022-03-03 10:15:25 +00:00
|
|
|
DIFlags::FlagZero,
|
|
|
|
data_ptr_type_di_node,
|
2022-11-18 18:41:53 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
),
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
|
|
|
owner,
|
|
|
|
extra_field_name,
|
|
|
|
(extra_field.size, extra_field.align.abi),
|
2024-10-03 13:05:23 +00:00
|
|
|
layout.fields.offset(abi::WIDE_PTR_EXTRA),
|
2022-03-03 10:15:25 +00:00
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, extra_field.ty),
|
2022-11-18 18:41:53 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
),
|
|
|
|
]
|
2022-01-13 17:13:54 +00:00
|
|
|
},
|
2022-03-03 10:15:25 +00:00
|
|
|
NO_GENERICS,
|
2022-01-13 17:13:54 +00:00
|
|
|
)
|
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_subroutine_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2024-09-18 03:34:49 +00:00
|
|
|
// It's possible to create a self-referential type in Rust by using 'impl trait':
|
2022-02-04 12:19:55 +00:00
|
|
|
//
|
|
|
|
// fn foo() -> impl Copy { foo }
|
|
|
|
//
|
|
|
|
// Unfortunately LLVM's API does not allow us to create recursive subroutine types.
|
|
|
|
// In order to work around that restriction we place a marker type in the type map,
|
|
|
|
// before creating the actual type. If the actual type is recursive, it will hit the
|
|
|
|
// marker type. So we end up with a type that looks like
|
|
|
|
//
|
|
|
|
// fn foo() -> <recursive_type>
|
|
|
|
//
|
|
|
|
// Once that is created, we replace the marker in the typemap with the actual type.
|
|
|
|
debug_context(cx)
|
|
|
|
.type_map
|
2022-03-03 10:15:25 +00:00
|
|
|
.unique_id_to_di_node
|
2022-02-04 12:19:55 +00:00
|
|
|
.borrow_mut()
|
2022-03-03 10:15:25 +00:00
|
|
|
.insert(unique_type_id, recursion_marker_type_di_node(cx));
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let fn_ty = unique_type_id.expect_ty();
|
2024-11-15 12:53:31 +00:00
|
|
|
let signature =
|
|
|
|
cx.tcx.normalize_erasing_late_bound_regions(cx.typing_env(), fn_ty.fn_sig(cx.tcx));
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let signature_di_nodes: SmallVec<_> = iter::once(
|
2018-07-26 15:11:10 +00:00
|
|
|
// return type
|
2020-08-02 22:49:11 +00:00
|
|
|
match signature.output().kind() {
|
2022-02-04 12:19:55 +00:00
|
|
|
ty::Tuple(tys) if tys.is_empty() => {
|
|
|
|
// this is a "void" function
|
|
|
|
None
|
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
_ => Some(type_di_node(cx, signature.output())),
|
2019-12-24 22:38:22 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
.chain(
|
2018-07-26 15:11:10 +00:00
|
|
|
// regular arguments
|
2022-03-03 10:15:25 +00:00
|
|
|
signature.inputs().iter().map(|&argument_type| Some(type_di_node(cx, argument_type))),
|
2019-12-24 22:38:22 +00:00
|
|
|
)
|
|
|
|
.collect();
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_context(cx).type_map.unique_id_to_di_node.borrow_mut().remove(&unique_type_id);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let fn_di_node = unsafe {
|
2022-02-04 12:19:55 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateSubroutineType(
|
|
|
|
DIB(cx),
|
2022-03-03 10:15:25 +00:00
|
|
|
create_DIArray(DIB(cx), &signature_di_nodes[..]),
|
2022-02-04 12:19:55 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
// This is actually a function pointer, so wrap it in pointer DI.
|
|
|
|
let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
|
2023-09-18 16:29:50 +00:00
|
|
|
let (size, align) = match fn_ty.kind() {
|
|
|
|
ty::FnDef(..) => (0, 1),
|
|
|
|
ty::FnPtr(..) => (
|
|
|
|
cx.tcx.data_layout.pointer_size.bits(),
|
|
|
|
cx.tcx.data_layout.pointer_align.abi.bits() as u32,
|
|
|
|
),
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2022-03-03 10:15:25 +00:00
|
|
|
let di_node = unsafe {
|
2022-02-04 12:19:55 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreatePointerType(
|
|
|
|
DIB(cx),
|
2022-03-03 10:15:25 +00:00
|
|
|
fn_di_node,
|
2023-09-18 16:29:50 +00:00
|
|
|
size,
|
|
|
|
align,
|
2022-02-04 12:19:55 +00:00
|
|
|
0, // Ignore DWARF address space.
|
2024-10-28 07:52:39 +00:00
|
|
|
name.as_c_char_ptr(),
|
2022-02-04 12:19:55 +00:00
|
|
|
name.len(),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
DINodeCreationResult::new(di_node, false)
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-01-21 09:35:18 +00:00
|
|
|
/// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
|
|
|
|
/// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_dyn_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-01-13 17:13:54 +00:00
|
|
|
dyn_type: Ty<'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-01-13 17:13:54 +00:00
|
|
|
if let ty::Dynamic(..) = dyn_type.kind() {
|
|
|
|
let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true);
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
|
|
|
cx,
|
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&type_name,
|
2022-11-17 02:31:30 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
cx.size_and_align_of(dyn_type),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
|_, _| smallvec![],
|
|
|
|
NO_GENERICS,
|
|
|
|
)
|
2022-01-13 17:13:54 +00:00
|
|
|
} else {
|
2022-03-14 16:11:58 +00:00
|
|
|
bug!(
|
|
|
|
"Only ty::Dynamic is valid for build_dyn_type_di_node(). Found {:?} instead.",
|
|
|
|
dyn_type
|
|
|
|
)
|
2022-01-13 17:13:54 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-01-21 09:35:18 +00:00
|
|
|
/// Create debuginfo for `[T]` and `str`. These are unsized.
|
|
|
|
///
|
2022-01-27 15:55:48 +00:00
|
|
|
/// NOTE: We currently emit just emit the debuginfo for the element type here
|
|
|
|
/// (i.e. `T` for slices and `u8` for `str`), so that we end up with
|
2024-10-03 13:05:23 +00:00
|
|
|
/// `*const T` for the `data_ptr` field of the corresponding wide-pointer
|
2022-01-27 15:55:48 +00:00
|
|
|
/// debuginfo of `&[T]`.
|
2022-01-21 09:35:18 +00:00
|
|
|
///
|
2022-01-27 15:55:48 +00:00
|
|
|
/// It would be preferable and more accurate if we emitted a DIArray of T
|
|
|
|
/// without an upper bound instead. That is, LLVM already supports emitting
|
|
|
|
/// debuginfo of arrays of unknown size. But GDB currently seems to end up
|
|
|
|
/// in an infinite loop when confronted with such a type.
|
2022-01-21 09:35:18 +00:00
|
|
|
///
|
2022-01-27 15:55:48 +00:00
|
|
|
/// As a side effect of the current encoding every instance of a type like
|
|
|
|
/// `struct Foo { unsized_field: [u8] }` will look like
|
|
|
|
/// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the
|
|
|
|
/// slice is zero, then accessing `unsized_field` in the debugger would
|
|
|
|
/// result in an out-of-bounds access.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_slice_type_di_node<'ll, 'tcx>(
|
2022-01-13 17:13:54 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
slice_type: Ty<'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-01-13 17:13:54 +00:00
|
|
|
let element_type = match slice_type.kind() {
|
Overhaul `TyS` and `Ty`.
Specifically, change `Ty` from this:
```
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
```
to this
```
pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>);
```
There are two benefits to this.
- It's now a first class type, so we can define methods on it. This
means we can move a lot of methods away from `TyS`, leaving `TyS` as a
barely-used type, which is appropriate given that it's not meant to
be used directly.
- The uniqueness requirement is now explicit, via the `Interned` type.
E.g. the pointer-based `Eq` and `Hash` comes from `Interned`, rather
than via `TyS`, which wasn't obvious at all.
Much of this commit is boring churn. The interesting changes are in
these files:
- compiler/rustc_middle/src/arena.rs
- compiler/rustc_middle/src/mir/visit.rs
- compiler/rustc_middle/src/ty/context.rs
- compiler/rustc_middle/src/ty/mod.rs
Specifically:
- Most mentions of `TyS` are removed. It's very much a dumb struct now;
`Ty` has all the smarts.
- `TyS` now has `crate` visibility instead of `pub`.
- `TyS::make_for_test` is removed in favour of the static `BOOL_TY`,
which just works better with the new structure.
- The `Eq`/`Ord`/`Hash` impls are removed from `TyS`. `Interned`s impls
of `Eq`/`Hash` now suffice. `Ord` is now partly on `Interned`
(pointer-based, for the `Equal` case) and partly on `TyS`
(contents-based, for the other cases).
- There are many tedious sigil adjustments, i.e. adding or removing `*`
or `&`. They seem to be unavoidable.
2022-01-25 03:13:38 +00:00
|
|
|
ty::Slice(element_type) => *element_type,
|
2022-01-13 17:13:54 +00:00
|
|
|
ty::Str => cx.tcx.types.u8,
|
|
|
|
_ => {
|
|
|
|
bug!(
|
2022-03-14 16:11:58 +00:00
|
|
|
"Only ty::Slice is valid for build_slice_type_di_node(). Found {:?} instead.",
|
2022-01-13 17:13:54 +00:00
|
|
|
slice_type
|
|
|
|
)
|
|
|
|
}
|
Improve debug symbol names to avoid ambiguity and work better with MSVC's debugger
There are several cases where names of types and functions in the debug info are either ambiguous, or not helpful, such as including ambiguous placeholders (e.g., `{{impl}}`, `{{closure}}` or `dyn _'`) or dropping qualifications (e.g., for dynamic types).
Instead, each debug symbol name should be unique and useful:
* Include disambiguators for anonymous `DefPathDataName` (closures and generators), and unify their formatting when used as a path-qualifier vs item being qualified.
* Qualify the principal trait for dynamic types.
* If there is no principal trait for a dynamic type, emit all other traits instead.
* Respect the `qualified` argument when emitting ref and pointer types.
* For implementations, emit the disambiguator.
* Print const generics when emitting generic parameters or arguments.
Additionally, when targeting MSVC, its debugger treats many command arguments as C++ expressions, even when the argument is defined to be a symbol name. As such names in the debug info need to be more C++-like to be parsed correctly:
* Avoid characters with special meaning (`#`, `[`, `"`, `+`).
* Never start a name with `<` or `{` as this is treated as an operator.
* `>>` is always treated as a right-shift, even when parsing generic arguments (so add a space to avoid this).
* Emit function declarations using C/C++ style syntax (e.g., leading return type).
* Emit arrays as a synthetic `array$<type, size>` type.
* Include a `$` in all synthetic types as this is a legal character for C++, but not Rust (thus we avoid collisions with user types).
2021-06-24 17:36:28 +00:00
|
|
|
};
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-14 16:11:58 +00:00
|
|
|
let element_type_di_node = type_di_node(cx, element_type);
|
2022-03-03 10:15:25 +00:00
|
|
|
return_if_di_node_created_in_meantime!(cx, unique_type_id);
|
2022-03-14 16:11:58 +00:00
|
|
|
DINodeCreationResult { di_node: element_type_di_node, already_stored_in_typemap: false }
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Get the debuginfo node for the given type.
|
|
|
|
///
|
|
|
|
/// This function will look up the debuginfo node in the TypeMap. If it can't find it, it
|
|
|
|
/// will create the node by dispatching to the corresponding `build_*_di_node()` function.
|
2024-07-06 12:26:42 +00:00
|
|
|
pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
|
2022-02-04 12:19:55 +00:00
|
|
|
let unique_type_id = UniqueTypeId::for_ty(cx.tcx, t);
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
if let Some(existing_di_node) = debug_context(cx).type_map.di_node_for_unique_id(unique_type_id)
|
|
|
|
{
|
|
|
|
return existing_di_node;
|
2022-02-04 12:19:55 +00:00
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2023-06-09 19:21:39 +00:00
|
|
|
debug!("type_di_node: {:?} kind: {:?}", t, t.kind());
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() {
|
2019-12-24 22:38:22 +00:00
|
|
|
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
|
2022-04-22 10:07:32 +00:00
|
|
|
build_basic_type_di_node(cx, t)
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
2022-04-22 10:07:32 +00:00
|
|
|
ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
|
2022-03-03 10:15:25 +00:00
|
|
|
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
|
|
|
|
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
|
|
|
|
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
|
|
|
|
ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id),
|
2024-03-21 21:11:06 +00:00
|
|
|
ty::RawPtr(pointee_type, _) | ty::Ref(_, pointee_type, _) => {
|
2022-03-03 10:15:25 +00:00
|
|
|
build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id)
|
2022-01-13 17:13:54 +00:00
|
|
|
}
|
2024-03-05 10:32:03 +00:00
|
|
|
// Some `Box` are newtyped pointers, make debuginfo aware of that.
|
|
|
|
// Only works if the allocator argument is a 1-ZST and hence irrelevant for layout
|
|
|
|
// (or if there is no allocator argument).
|
|
|
|
ty::Adt(def, args)
|
|
|
|
if def.is_box()
|
|
|
|
&& args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) =>
|
|
|
|
{
|
2024-09-04 21:34:04 +00:00
|
|
|
build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id)
|
2016-12-26 13:34:03 +00:00
|
|
|
}
|
2024-08-08 07:18:20 +00:00
|
|
|
ty::FnDef(..) | ty::FnPtr(..) => build_subroutine_type_di_node(cx, unique_type_id),
|
2022-03-03 10:15:25 +00:00
|
|
|
ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id),
|
2024-02-09 15:53:55 +00:00
|
|
|
ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id),
|
2023-10-19 21:46:28 +00:00
|
|
|
ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id),
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::Adt(def, ..) => match def.adt_kind() {
|
2022-03-03 10:15:25 +00:00
|
|
|
AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id),
|
|
|
|
AdtKind::Union => build_union_type_di_node(cx, unique_type_id),
|
|
|
|
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id),
|
2016-09-05 22:26:02 +00:00
|
|
|
},
|
2022-03-03 10:15:25 +00:00
|
|
|
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
|
2022-03-14 16:11:58 +00:00
|
|
|
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
{
|
|
|
|
if already_stored_in_typemap {
|
2022-02-04 12:19:55 +00:00
|
|
|
// Make sure that we really do have a `TypeMap` entry for the unique type ID.
|
2022-03-03 10:15:25 +00:00
|
|
|
let di_node_for_uid =
|
|
|
|
match debug_context(cx).type_map.di_node_for_unique_id(unique_type_id) {
|
|
|
|
Some(di_node) => di_node,
|
2022-02-04 12:19:55 +00:00
|
|
|
None => {
|
2022-01-10 14:59:52 +00:00
|
|
|
bug!(
|
2022-03-14 16:11:58 +00:00
|
|
|
"expected type debuginfo node for unique \
|
2022-02-04 12:19:55 +00:00
|
|
|
type ID '{:?}' to already be in \
|
|
|
|
the `debuginfo::TypeMap` but it \
|
2022-02-24 16:19:18 +00:00
|
|
|
was not.",
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id,
|
2019-12-24 22:38:22 +00:00
|
|
|
);
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
2022-02-04 12:19:55 +00:00
|
|
|
};
|
|
|
|
|
2024-07-19 23:52:33 +00:00
|
|
|
assert_eq!(di_node_for_uid as *const _, di_node as *const _);
|
2015-04-24 04:48:10 +00:00
|
|
|
} else {
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_context(cx).type_map.insert(unique_type_id, di_node);
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
di_node
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
// FIXME(mw): Cache this via a regular UniqueTypeId instead of an extra field in the debug context.
|
|
|
|
fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll DIType {
|
2022-02-04 12:19:55 +00:00
|
|
|
*debug_context(cx).recursion_marker_type.get_or_init(move || {
|
|
|
|
unsafe {
|
|
|
|
// The choice of type here is pretty arbitrary -
|
|
|
|
// anything reading the debuginfo for a recursive
|
|
|
|
// type is going to see *something* weird - the only
|
|
|
|
// question is what exactly it will see.
|
|
|
|
//
|
|
|
|
// FIXME: the name `<recur_type>` does not fit the naming scheme
|
|
|
|
// of other types.
|
2022-02-24 16:19:18 +00:00
|
|
|
//
|
|
|
|
// FIXME: it might make sense to use an actual pointer type here
|
|
|
|
// so that debuggers can show the address.
|
2022-02-04 12:19:55 +00:00
|
|
|
let name = "<recur_type>";
|
|
|
|
llvm::LLVMRustDIBuilderCreateBasicType(
|
|
|
|
DIB(cx),
|
2024-10-28 07:52:39 +00:00
|
|
|
name.as_c_char_ptr(),
|
2022-02-04 12:19:55 +00:00
|
|
|
name.len(),
|
|
|
|
cx.tcx.data_layout.pointer_size.bits(),
|
2025-01-05 00:38:43 +00:00
|
|
|
dwarf_const::DW_ATE_unsigned,
|
2022-02-04 12:19:55 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-03-31 05:17:15 +00:00
|
|
|
fn hex_encode(data: &[u8]) -> String {
|
|
|
|
let mut hex_string = String::with_capacity(data.len() * 2);
|
|
|
|
for byte in data.iter() {
|
2023-07-25 21:04:01 +00:00
|
|
|
write!(&mut hex_string, "{byte:02x}").unwrap();
|
2020-03-31 05:17:15 +00:00
|
|
|
}
|
|
|
|
hex_string
|
|
|
|
}
|
|
|
|
|
2024-07-06 12:26:42 +00:00
|
|
|
pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
|
2023-12-19 21:34:26 +00:00
|
|
|
let cache_key = Some((source_file.stable_id, source_file.src_hash));
|
2022-05-05 15:26:22 +00:00
|
|
|
return debug_context(cx)
|
|
|
|
.created_files
|
|
|
|
.borrow_mut()
|
|
|
|
.entry(cache_key)
|
|
|
|
.or_insert_with(|| alloc_new_file_metadata(cx, source_file));
|
|
|
|
|
|
|
|
#[instrument(skip(cx, source_file), level = "debug")]
|
|
|
|
fn alloc_new_file_metadata<'ll>(
|
|
|
|
cx: &CodegenCx<'ll, '_>,
|
|
|
|
source_file: &SourceFile,
|
|
|
|
) -> &'ll DIFile {
|
|
|
|
debug!(?source_file.name);
|
|
|
|
|
2024-03-22 14:27:17 +00:00
|
|
|
let filename_display_preference =
|
|
|
|
cx.sess().filename_display_preference(RemapPathScopeComponents::DEBUGINFO);
|
|
|
|
|
|
|
|
use rustc_session::config::RemapPathScopeComponents;
|
2022-05-05 15:26:22 +00:00
|
|
|
let (directory, file_name) = match &source_file.name {
|
|
|
|
FileName::Real(filename) => {
|
|
|
|
let working_directory = &cx.sess().opts.working_dir;
|
|
|
|
debug!(?working_directory);
|
|
|
|
|
2024-03-22 14:27:17 +00:00
|
|
|
if filename_display_preference == FileNameDisplayPreference::Remapped {
|
2023-08-23 13:46:58 +00:00
|
|
|
let filename = cx
|
|
|
|
.sess()
|
|
|
|
.source_map()
|
|
|
|
.path_mapping()
|
|
|
|
.to_embeddable_absolute_path(filename.clone(), working_directory);
|
|
|
|
|
|
|
|
// Construct the absolute path of the file
|
|
|
|
let abs_path = filename.remapped_path_if_available();
|
|
|
|
debug!(?abs_path);
|
|
|
|
|
|
|
|
if let Ok(rel_path) =
|
|
|
|
abs_path.strip_prefix(working_directory.remapped_path_if_available())
|
|
|
|
{
|
|
|
|
// If the compiler's working directory (which also is the DW_AT_comp_dir of
|
|
|
|
// the compilation unit) is a prefix of the path we are about to emit, then
|
2024-09-18 03:34:49 +00:00
|
|
|
// only emit the part relative to the working directory. Because of path
|
|
|
|
// remapping we sometimes see strange things here: `abs_path` might
|
|
|
|
// actually look like a relative path (e.g.
|
|
|
|
// `<crate-name-and-version>/src/lib.rs`), so if we emit it without taking
|
|
|
|
// the working directory into account, downstream tooling will interpret it
|
|
|
|
// as `<working-directory>/<crate-name-and-version>/src/lib.rs`, which
|
|
|
|
// makes no sense. Usually in such cases the working directory will also be
|
|
|
|
// remapped to `<crate-name-and-version>` or some other prefix of the path
|
2023-08-23 13:46:58 +00:00
|
|
|
// we are remapping, so we end up with
|
|
|
|
// `<crate-name-and-version>/<crate-name-and-version>/src/lib.rs`.
|
|
|
|
// By moving the working directory portion into the `directory` part of the
|
|
|
|
// DIFile, we allow LLVM to emit just the relative path for DWARF, while
|
|
|
|
// still emitting the correct absolute path for CodeView.
|
|
|
|
(
|
|
|
|
working_directory.to_string_lossy(FileNameDisplayPreference::Remapped),
|
|
|
|
rel_path.to_string_lossy().into_owned(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
("".into(), abs_path.to_string_lossy().into_owned())
|
|
|
|
}
|
2022-05-05 15:26:22 +00:00
|
|
|
} else {
|
2023-08-23 13:46:58 +00:00
|
|
|
let working_directory = working_directory.local_path_if_available();
|
|
|
|
let filename = filename.local_path_if_available();
|
|
|
|
|
|
|
|
debug!(?working_directory, ?filename);
|
|
|
|
|
|
|
|
let abs_path: Cow<'_, Path> = if filename.is_absolute() {
|
|
|
|
filename.into()
|
|
|
|
} else {
|
|
|
|
let mut p = PathBuf::new();
|
|
|
|
p.push(working_directory);
|
|
|
|
p.push(filename);
|
|
|
|
p.into()
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Ok(rel_path) = abs_path.strip_prefix(working_directory) {
|
|
|
|
(
|
2023-12-15 22:56:24 +00:00
|
|
|
working_directory.to_string_lossy(),
|
2023-08-23 13:46:58 +00:00
|
|
|
rel_path.to_string_lossy().into_owned(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
("".into(), abs_path.to_string_lossy().into_owned())
|
|
|
|
}
|
2020-03-31 05:17:15 +00:00
|
|
|
}
|
2022-05-05 15:26:22 +00:00
|
|
|
}
|
2023-08-23 13:46:58 +00:00
|
|
|
other => {
|
|
|
|
debug!(?other);
|
2024-03-22 14:27:17 +00:00
|
|
|
("".into(), other.display(filename_display_preference).to_string())
|
2023-08-23 13:46:58 +00:00
|
|
|
}
|
2022-05-05 15:26:22 +00:00
|
|
|
};
|
2020-03-31 05:17:15 +00:00
|
|
|
|
2022-05-05 15:26:22 +00:00
|
|
|
let hash_kind = match source_file.src_hash.kind {
|
|
|
|
rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
|
|
|
|
rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
|
|
|
|
rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
|
2024-06-22 07:27:59 +00:00
|
|
|
rustc_span::SourceFileHashAlgorithm::Blake3 => llvm::ChecksumKind::None,
|
2022-05-05 15:26:22 +00:00
|
|
|
};
|
|
|
|
let hash_value = hex_encode(source_file.src_hash.hash_bytes());
|
2017-04-24 17:01:19 +00:00
|
|
|
|
2024-04-27 21:14:36 +00:00
|
|
|
let source =
|
|
|
|
cx.sess().opts.unstable_opts.embed_source.then_some(()).and(source_file.src.as_ref());
|
|
|
|
|
2022-05-05 15:26:22 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRustDIBuilderCreateFile(
|
|
|
|
DIB(cx),
|
2024-10-28 07:52:39 +00:00
|
|
|
file_name.as_c_char_ptr(),
|
2022-05-05 15:26:22 +00:00
|
|
|
file_name.len(),
|
2024-10-28 07:52:39 +00:00
|
|
|
directory.as_c_char_ptr(),
|
2022-05-05 15:26:22 +00:00
|
|
|
directory.len(),
|
|
|
|
hash_kind,
|
2024-10-28 07:52:39 +00:00
|
|
|
hash_value.as_c_char_ptr(),
|
2022-05-05 15:26:22 +00:00
|
|
|
hash_value.len(),
|
2024-10-28 07:52:39 +00:00
|
|
|
source.map_or(ptr::null(), |x| x.as_c_char_ptr()),
|
2024-04-27 21:14:36 +00:00
|
|
|
source.map_or(0, |x| x.len()),
|
2022-05-05 15:26:22 +00:00
|
|
|
)
|
2019-05-06 01:47:03 +00:00
|
|
|
}
|
Workaround ODR violations in enum debuginfo
When using a generic enum type that was defined in an external crate,
our debuginfo currently claims that the concrete type (e.g. Option<i32>)
was defined in the current crate, where it was first used.
This means that if there are multiple crates that all use, for example,
Option<i32> values, they'll have conflicting debuginfo, each crate
claiming to have defined that type. This doesn't cause problems in
regular builds, but with LTO enabled, LLVM complains because it tries to
merge the debuginfo for those types and sees the ODR violations.
Since I couldn't find a way to get the file info for the external crate
that actually defined the enum, I'm working around the issue by using
"<unknown>" as the file for enum types. We'll want to re-visit and fix
this later, but this at least this fixes the ICE. And with the file
being unknown instead of wrong, the debuginfo isn't really worse than
before either.
Fixes #26447
2015-07-29 11:53:59 +00:00
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2024-07-06 12:26:42 +00:00
|
|
|
fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
|
2022-05-05 15:26:22 +00:00
|
|
|
debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| unsafe {
|
|
|
|
let file_name = "<unknown>";
|
|
|
|
let directory = "";
|
|
|
|
let hash_value = "";
|
|
|
|
|
|
|
|
llvm::LLVMRustDIBuilderCreateFile(
|
|
|
|
DIB(cx),
|
2024-10-28 07:52:39 +00:00
|
|
|
file_name.as_c_char_ptr(),
|
2022-05-05 15:26:22 +00:00
|
|
|
file_name.len(),
|
2024-10-28 07:52:39 +00:00
|
|
|
directory.as_c_char_ptr(),
|
2022-05-05 15:26:22 +00:00
|
|
|
directory.len(),
|
|
|
|
llvm::ChecksumKind::None,
|
2024-10-28 07:52:39 +00:00
|
|
|
hash_value.as_c_char_ptr(),
|
2022-05-05 15:26:22 +00:00
|
|
|
hash_value.len(),
|
2024-04-27 21:14:36 +00:00
|
|
|
ptr::null(),
|
|
|
|
0,
|
2022-05-05 15:26:22 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-25 06:28:00 +00:00
|
|
|
trait MsvcBasicName {
|
|
|
|
fn msvc_basic_name(self) -> &'static str;
|
|
|
|
}
|
|
|
|
|
2020-12-12 14:32:30 +00:00
|
|
|
impl MsvcBasicName for ty::IntTy {
|
2020-06-25 06:28:00 +00:00
|
|
|
fn msvc_basic_name(self) -> &'static str {
|
|
|
|
match self {
|
2020-12-12 14:32:30 +00:00
|
|
|
ty::IntTy::Isize => "ptrdiff_t",
|
|
|
|
ty::IntTy::I8 => "__int8",
|
|
|
|
ty::IntTy::I16 => "__int16",
|
|
|
|
ty::IntTy::I32 => "__int32",
|
|
|
|
ty::IntTy::I64 => "__int64",
|
|
|
|
ty::IntTy::I128 => "__int128",
|
2020-06-25 06:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 14:32:30 +00:00
|
|
|
impl MsvcBasicName for ty::UintTy {
|
2020-06-25 06:28:00 +00:00
|
|
|
fn msvc_basic_name(self) -> &'static str {
|
|
|
|
match self {
|
2020-12-12 14:32:30 +00:00
|
|
|
ty::UintTy::Usize => "size_t",
|
|
|
|
ty::UintTy::U8 => "unsigned __int8",
|
|
|
|
ty::UintTy::U16 => "unsigned __int16",
|
|
|
|
ty::UintTy::U32 => "unsigned __int32",
|
|
|
|
ty::UintTy::U64 => "unsigned __int64",
|
|
|
|
ty::UintTy::U128 => "unsigned __int128",
|
2020-06-25 06:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 14:32:30 +00:00
|
|
|
impl MsvcBasicName for ty::FloatTy {
|
2020-06-25 06:28:00 +00:00
|
|
|
fn msvc_basic_name(self) -> &'static str {
|
2024-06-26 17:18:32 +00:00
|
|
|
// FIXME(f16_f128): `f16` and `f128` have no MSVC representation. We could improve the
|
|
|
|
// debuginfo. See: <https://github.com/rust-lang/rust/issues/121837>
|
2020-06-25 06:28:00 +00:00
|
|
|
match self {
|
2024-06-26 17:18:32 +00:00
|
|
|
ty::FloatTy::F16 => {
|
|
|
|
bug!("`f16` should have been handled in `build_basic_type_di_node`")
|
|
|
|
}
|
2020-12-12 14:32:30 +00:00
|
|
|
ty::FloatTy::F32 => "float",
|
|
|
|
ty::FloatTy::F64 => "double",
|
2024-02-28 08:44:23 +00:00
|
|
|
ty::FloatTy::F128 => "fp128",
|
2020-06-25 06:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-26 17:18:32 +00:00
|
|
|
fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreationResult<'ll> {
|
|
|
|
// MSVC has no native support for `f16`. Instead, emit `struct f16 { bits: u16 }` to allow the
|
|
|
|
// `f16`'s value to be displayed using a Natvis visualiser in `intrinsic.natvis`.
|
|
|
|
let float_ty = cx.tcx.types.f16;
|
|
|
|
let bits_ty = cx.tcx.types.u16;
|
2024-11-07 02:38:51 +00:00
|
|
|
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
|
|
|
match float_ty.kind() {
|
|
|
|
ty::Adt(def, _) => Some(file_metadata_from_def_id(cx, Some(def.did()))),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2024-06-26 17:18:32 +00:00
|
|
|
type_map::build_type_with_children(
|
|
|
|
cx,
|
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
UniqueTypeId::for_ty(cx.tcx, float_ty),
|
|
|
|
"f16",
|
2024-11-07 02:38:51 +00:00
|
|
|
def_location,
|
2024-06-26 17:18:32 +00:00
|
|
|
cx.size_and_align_of(float_ty),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
// Fields:
|
|
|
|
|cx, float_di_node| {
|
2024-11-07 02:38:51 +00:00
|
|
|
let def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
|
|
|
match bits_ty.kind() {
|
|
|
|
ty::Adt(def, _) => Some(def.did()),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2024-06-26 17:18:32 +00:00
|
|
|
smallvec![build_field_di_node(
|
|
|
|
cx,
|
|
|
|
float_di_node,
|
|
|
|
"bits",
|
|
|
|
cx.size_and_align_of(bits_ty),
|
|
|
|
Size::ZERO,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, bits_ty),
|
2024-11-07 02:38:51 +00:00
|
|
|
def_id,
|
2024-06-26 17:18:32 +00:00
|
|
|
)]
|
|
|
|
},
|
|
|
|
NO_GENERICS,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-04-22 10:07:32 +00:00
|
|
|
fn build_basic_type_di_node<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
t: Ty<'tcx>,
|
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-03-03 10:15:25 +00:00
|
|
|
debug!("build_basic_type_di_node: {:?}", t);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2020-06-25 06:28:00 +00:00
|
|
|
// When targeting MSVC, emit MSVC style type names for compatibility with
|
|
|
|
// .natvis visualizers (and perhaps other existing native debuggers?)
|
2021-12-28 21:57:18 +00:00
|
|
|
let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx);
|
2020-06-25 06:28:00 +00:00
|
|
|
|
2025-01-05 00:38:43 +00:00
|
|
|
use dwarf_const::{DW_ATE_UTF, DW_ATE_boolean, DW_ATE_float, DW_ATE_signed, DW_ATE_unsigned};
|
|
|
|
|
2020-08-02 22:49:11 +00:00
|
|
|
let (name, encoding) = match t.kind() {
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::Never => ("!", DW_ATE_unsigned),
|
2022-04-22 10:07:32 +00:00
|
|
|
ty::Tuple(elements) if elements.is_empty() => {
|
|
|
|
if cpp_like_debuginfo {
|
|
|
|
return build_tuple_type_di_node(cx, UniqueTypeId::for_ty(cx.tcx, t));
|
|
|
|
} else {
|
|
|
|
("()", DW_ATE_unsigned)
|
|
|
|
}
|
|
|
|
}
|
2018-08-22 00:35:55 +00:00
|
|
|
ty::Bool => ("bool", DW_ATE_boolean),
|
2021-10-14 17:26:42 +00:00
|
|
|
ty::Char => ("char", DW_ATE_UTF),
|
2021-12-28 21:57:18 +00:00
|
|
|
ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
|
|
|
|
ty::Uint(uint_ty) if cpp_like_debuginfo => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
|
2024-06-26 17:18:32 +00:00
|
|
|
ty::Float(ty::FloatTy::F16) if cpp_like_debuginfo => {
|
|
|
|
return build_cpp_f16_di_node(cx);
|
|
|
|
}
|
2021-12-28 21:57:18 +00:00
|
|
|
ty::Float(float_ty) if cpp_like_debuginfo => (float_ty.msvc_basic_name(), DW_ATE_float),
|
2019-12-24 22:38:22 +00:00
|
|
|
ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed),
|
|
|
|
ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned),
|
|
|
|
ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float),
|
2022-03-03 10:15:25 +00:00
|
|
|
_ => bug!("debuginfo::build_basic_type_di_node - `t` is invalid type"),
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let ty_di_node = unsafe {
|
2016-08-01 23:35:09 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateBasicType(
|
2015-04-24 04:48:10 +00:00
|
|
|
DIB(cx),
|
2024-10-28 07:52:39 +00:00
|
|
|
name.as_c_char_ptr(),
|
2020-03-06 00:00:00 +00:00
|
|
|
name.len(),
|
2020-05-21 17:53:41 +00:00
|
|
|
cx.size_of(t).bits(),
|
2019-12-24 22:38:22 +00:00
|
|
|
encoding,
|
|
|
|
)
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
2021-12-28 21:57:18 +00:00
|
|
|
if !cpp_like_debuginfo {
|
2022-04-22 10:07:32 +00:00
|
|
|
return DINodeCreationResult::new(ty_di_node, false);
|
2020-06-25 06:28:00 +00:00
|
|
|
}
|
|
|
|
|
2020-08-02 22:49:11 +00:00
|
|
|
let typedef_name = match t.kind() {
|
2020-06-25 06:28:00 +00:00
|
|
|
ty::Int(int_ty) => int_ty.name_str(),
|
|
|
|
ty::Uint(uint_ty) => uint_ty.name_str(),
|
|
|
|
ty::Float(float_ty) => float_ty.name_str(),
|
2022-04-22 10:07:32 +00:00
|
|
|
_ => return DINodeCreationResult::new(ty_di_node, false),
|
2020-06-25 06:28:00 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let typedef_di_node = unsafe {
|
2020-06-25 06:28:00 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateTypedef(
|
|
|
|
DIB(cx),
|
2022-03-03 10:15:25 +00:00
|
|
|
ty_di_node,
|
2024-10-28 07:52:39 +00:00
|
|
|
typedef_name.as_c_char_ptr(),
|
2020-06-25 06:28:00 +00:00
|
|
|
typedef_name.len(),
|
|
|
|
unknown_file_metadata(cx),
|
|
|
|
0,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2022-04-22 10:07:32 +00:00
|
|
|
DINodeCreationResult::new(typedef_di_node, false)
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_foreign_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
t: Ty<'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
debug!("build_foreign_type_di_node: {:?}", t);
|
|
|
|
|
|
|
|
let &ty::Foreign(def_id) = unique_type_id.expect_ty().kind() else {
|
|
|
|
bug!(
|
|
|
|
"build_foreign_type_di_node() called with unexpected type: {:?}",
|
|
|
|
unique_type_id.expect_ty()
|
|
|
|
);
|
|
|
|
};
|
2017-09-03 18:53:58 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
build_type_with_children(
|
2022-01-25 13:26:50 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&compute_debuginfo_type_name(cx.tcx, t, false),
|
2022-11-17 02:31:30 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
cx.size_and_align_of(t),
|
|
|
|
Some(get_namespace_for_item(cx, def_id)),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
|_, _| smallvec![],
|
|
|
|
NO_GENERICS,
|
2022-01-25 13:26:50 +00:00
|
|
|
)
|
2017-09-03 18:53:58 +00:00
|
|
|
}
|
|
|
|
|
2024-07-06 12:26:42 +00:00
|
|
|
pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
2021-12-14 18:49:49 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-11 21:11:55 +00:00
|
|
|
codegen_unit_name: &str,
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_context: &CodegenUnitDebugContext<'ll, 'tcx>,
|
2019-06-11 21:11:55 +00:00
|
|
|
) -> &'ll DIDescriptor {
|
2024-03-19 12:51:22 +00:00
|
|
|
use rustc_session::RemapFileNameExt;
|
|
|
|
use rustc_session::config::RemapPathScopeComponents;
|
2022-12-07 09:24:00 +00:00
|
|
|
let mut name_in_debuginfo = tcx
|
|
|
|
.sess
|
|
|
|
.local_crate_source_file()
|
2024-03-19 12:51:22 +00:00
|
|
|
.map(|src| src.for_scope(&tcx.sess, RemapPathScopeComponents::DEBUGINFO).to_path_buf())
|
2022-12-07 09:24:00 +00:00
|
|
|
.unwrap_or_else(|| PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()));
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2021-12-17 04:39:41 +00:00
|
|
|
// To avoid breaking split DWARF, we need to ensure that each codegen unit
|
|
|
|
// has a unique `DW_AT_name`. This is because there's a remote chance that
|
|
|
|
// different codegen units for the same module will have entirely
|
|
|
|
// identical DWARF entries for the purpose of the DWO ID, which would
|
|
|
|
// violate Appendix F ("Split Dwarf Object Files") of the DWARF 5
|
|
|
|
// specification. LLVM uses the algorithm specified in section 7.32 "Type
|
|
|
|
// Signature Computation" to compute the DWO ID, which does not include
|
|
|
|
// any fields that would distinguish compilation units. So we must embed
|
|
|
|
// the codegen unit name into the `DW_AT_name`. (Issue #88521.)
|
|
|
|
//
|
|
|
|
// Additionally, the OSX linker has an idiosyncrasy where it will ignore
|
|
|
|
// some debuginfo if multiple object files with the same `DW_AT_name` are
|
|
|
|
// linked together.
|
|
|
|
//
|
|
|
|
// As a workaround for these two issues, we generate unique names for each
|
|
|
|
// object file. Those do not correspond to an actual source file but that
|
|
|
|
// is harmless.
|
|
|
|
name_in_debuginfo.push("@");
|
|
|
|
name_in_debuginfo.push(codegen_unit_name);
|
2017-05-19 08:55:25 +00:00
|
|
|
|
2022-03-14 16:11:58 +00:00
|
|
|
debug!("build_compile_unit_di_node: {:?}", name_in_debuginfo);
|
2023-05-08 09:12:38 +00:00
|
|
|
let rustc_producer = format!("rustc version {}", tcx.sess.cfg_version);
|
2017-03-08 18:08:09 +00:00
|
|
|
// FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
|
2023-07-25 21:04:01 +00:00
|
|
|
let producer = format!("clang LLVM ({rustc_producer})");
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2018-08-07 14:04:34 +00:00
|
|
|
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
|
2024-03-19 12:51:22 +00:00
|
|
|
let work_dir = tcx
|
|
|
|
.sess
|
|
|
|
.opts
|
|
|
|
.working_dir
|
|
|
|
.for_scope(tcx.sess, RemapPathScopeComponents::DEBUGINFO)
|
|
|
|
.to_string_lossy();
|
2021-05-11 12:39:04 +00:00
|
|
|
let output_filenames = tcx.output_filenames(());
|
2024-03-21 20:13:06 +00:00
|
|
|
let split_name = if tcx.sess.target_can_use_split_dwarf()
|
|
|
|
&& let Some(f) = output_filenames.split_dwarf_path(
|
|
|
|
tcx.sess.split_debuginfo(),
|
|
|
|
tcx.sess.opts.unstable_opts.split_dwarf_kind,
|
|
|
|
Some(codegen_unit_name),
|
|
|
|
) {
|
|
|
|
// We get a path relative to the working directory from split_dwarf_path
|
|
|
|
Some(tcx.sess.source_map().path_mapping().to_real_filename(f))
|
2020-11-30 16:39:08 +00:00
|
|
|
} else {
|
|
|
|
None
|
2024-03-21 20:13:06 +00:00
|
|
|
};
|
|
|
|
let split_name = split_name
|
|
|
|
.as_ref()
|
|
|
|
.map(|f| f.for_scope(tcx.sess, RemapPathScopeComponents::DEBUGINFO).to_string_lossy())
|
|
|
|
.unwrap_or_default();
|
2021-04-06 20:00:35 +00:00
|
|
|
let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
|
2017-02-11 21:01:25 +00:00
|
|
|
|
2023-11-16 04:07:37 +00:00
|
|
|
let dwarf_version =
|
|
|
|
tcx.sess.opts.unstable_opts.dwarf_version.unwrap_or(tcx.sess.target.default_dwarf_version);
|
2023-12-11 21:24:24 +00:00
|
|
|
let is_dwarf_kind =
|
|
|
|
matches!(tcx.sess.target.debuginfo_kind, DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym);
|
2023-11-16 04:07:37 +00:00
|
|
|
// Don't emit `.debug_pubnames` and `.debug_pubtypes` on DWARFv4 or lower.
|
2023-12-11 21:24:24 +00:00
|
|
|
let debug_name_table_kind = if is_dwarf_kind && dwarf_version <= 4 {
|
|
|
|
DebugNameTableKind::None
|
|
|
|
} else {
|
|
|
|
DebugNameTableKind::Default
|
|
|
|
};
|
2023-11-16 04:07:37 +00:00
|
|
|
|
2017-02-11 21:01:25 +00:00
|
|
|
unsafe {
|
2021-02-14 15:12:14 +00:00
|
|
|
let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile(
|
2019-12-24 22:38:22 +00:00
|
|
|
debug_context.builder,
|
2024-10-28 07:52:39 +00:00
|
|
|
name_in_debuginfo.as_c_char_ptr(),
|
2020-03-06 00:00:00 +00:00
|
|
|
name_in_debuginfo.len(),
|
2024-10-28 07:52:39 +00:00
|
|
|
work_dir.as_c_char_ptr(),
|
2021-02-14 15:12:14 +00:00
|
|
|
work_dir.len(),
|
2020-03-31 05:17:15 +00:00
|
|
|
llvm::ChecksumKind::None,
|
|
|
|
ptr::null(),
|
|
|
|
0,
|
2024-04-27 21:14:36 +00:00
|
|
|
ptr::null(),
|
|
|
|
0,
|
2019-12-24 22:38:22 +00:00
|
|
|
);
|
2017-02-11 21:01:25 +00:00
|
|
|
|
2017-02-13 09:57:50 +00:00
|
|
|
let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
|
2016-07-12 22:40:38 +00:00
|
|
|
debug_context.builder,
|
2025-01-05 00:38:43 +00:00
|
|
|
dwarf_const::DW_LANG_Rust,
|
2021-02-14 15:12:14 +00:00
|
|
|
compile_unit_file,
|
2024-10-28 07:52:39 +00:00
|
|
|
producer.as_c_char_ptr(),
|
2020-03-06 00:00:00 +00:00
|
|
|
producer.len(),
|
2018-01-05 04:14:44 +00:00
|
|
|
tcx.sess.opts.optimize != config::OptLevel::No,
|
2024-08-20 21:04:48 +00:00
|
|
|
c"".as_ptr(),
|
2015-04-24 04:48:10 +00:00
|
|
|
0,
|
2021-02-14 15:12:14 +00:00
|
|
|
// NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead
|
|
|
|
// put the path supplied to `MCSplitDwarfFile` into the debug info of the final
|
|
|
|
// output(s).
|
2024-10-28 07:52:39 +00:00
|
|
|
split_name.as_c_char_ptr(),
|
2020-03-06 00:00:00 +00:00
|
|
|
split_name.len(),
|
2019-12-24 22:38:22 +00:00
|
|
|
kind,
|
2020-09-23 15:25:20 +00:00
|
|
|
0,
|
2022-07-06 12:44:47 +00:00
|
|
|
tcx.sess.opts.unstable_opts.split_dwarf_inlining,
|
2023-11-16 04:07:37 +00:00
|
|
|
debug_name_table_kind,
|
2019-12-24 22:38:22 +00:00
|
|
|
);
|
2017-02-13 09:57:50 +00:00
|
|
|
|
|
|
|
return unit_metadata;
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Creates a `DW_TAG_member` entry inside the DIE represented by the given `type_di_node`.
|
|
|
|
fn build_field_di_node<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
owner: &'ll DIScope,
|
|
|
|
name: &str,
|
|
|
|
size_and_align: (Size, Align),
|
2017-06-01 18:50:53 +00:00
|
|
|
offset: Size,
|
2016-11-18 22:15:14 +00:00
|
|
|
flags: DIFlags,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_di_node: &'ll DIType,
|
2022-11-18 18:41:53 +00:00
|
|
|
def_id: Option<DefId>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> &'ll DIType {
|
2024-03-02 04:33:46 +00:00
|
|
|
let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
|
|
|
|
{
|
|
|
|
file_metadata_from_def_id(cx, def_id)
|
|
|
|
} else {
|
|
|
|
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
|
|
|
|
};
|
2022-03-03 10:15:25 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRustDIBuilderCreateMemberType(
|
|
|
|
DIB(cx),
|
|
|
|
owner,
|
2024-10-28 07:52:39 +00:00
|
|
|
name.as_c_char_ptr(),
|
2022-03-03 10:15:25 +00:00
|
|
|
name.len(),
|
2022-11-18 18:41:53 +00:00
|
|
|
file_metadata,
|
|
|
|
line_number,
|
2022-03-03 10:15:25 +00:00
|
|
|
size_and_align.0.bits(),
|
|
|
|
size_and_align.1.bits() as u32,
|
|
|
|
offset.bits(),
|
|
|
|
flags,
|
|
|
|
type_di_node,
|
|
|
|
)
|
2015-04-29 06:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-23 14:29:23 +00:00
|
|
|
/// Returns the `DIFlags` corresponding to the visibility of the item identified by `did`.
|
|
|
|
///
|
|
|
|
/// `DIFlags::Flag{Public,Protected,Private}` correspond to `DW_AT_accessibility`
|
|
|
|
/// (public/protected/private) aren't exactly right for Rust, but neither is `DW_AT_visibility`
|
|
|
|
/// (local/exported/qualified), and there's no way to set `DW_AT_visibility` in LLVM's API.
|
|
|
|
fn visibility_di_flags<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
did: DefId,
|
|
|
|
type_did: DefId,
|
|
|
|
) -> DIFlags {
|
|
|
|
let parent_did = cx.tcx.parent(type_did);
|
|
|
|
let visibility = cx.tcx.visibility(did);
|
|
|
|
match visibility {
|
|
|
|
Visibility::Public => DIFlags::FlagPublic,
|
|
|
|
// Private fields have a restricted visibility of the module containing the type.
|
|
|
|
Visibility::Restricted(did) if did == parent_did => DIFlags::FlagPrivate,
|
|
|
|
// `pub(crate)`/`pub(super)` visibilities are any other restricted visibility.
|
|
|
|
Visibility::Restricted(..) => DIFlags::FlagProtected,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Creates the debuginfo node for a Rust struct type. Maybe be a regular struct or a tuple-struct.
|
|
|
|
fn build_struct_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let struct_type = unique_type_id.expect_ty();
|
|
|
|
let ty::Adt(adt_def, _) = struct_type.kind() else {
|
|
|
|
bug!("build_struct_type_di_node() called with non-struct-type: {:?}", struct_type);
|
2015-08-02 19:52:50 +00:00
|
|
|
};
|
2024-07-19 23:52:33 +00:00
|
|
|
assert!(adt_def.is_struct());
|
2022-03-03 10:15:25 +00:00
|
|
|
let containing_scope = get_namespace_for_item(cx, adt_def.did());
|
|
|
|
let struct_type_and_layout = cx.layout_of(struct_type);
|
|
|
|
let variant_def = adt_def.non_enum_variant();
|
2024-03-02 04:33:46 +00:00
|
|
|
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
2023-07-30 03:48:54 +00:00
|
|
|
Some(file_metadata_from_def_id(cx, Some(adt_def.did())))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2015-08-02 19:52:50 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
2020-06-18 02:39:23 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&compute_debuginfo_type_name(cx.tcx, struct_type, false),
|
2023-07-30 03:48:54 +00:00
|
|
|
def_location,
|
2022-03-03 10:15:25 +00:00
|
|
|
size_and_align_of(struct_type_and_layout),
|
|
|
|
Some(containing_scope),
|
2023-08-23 14:29:23 +00:00
|
|
|
visibility_di_flags(cx, adt_def.did(), adt_def.did()),
|
2022-03-03 10:15:25 +00:00
|
|
|
),
|
|
|
|
// Fields:
|
|
|
|
|cx, owner| {
|
|
|
|
variant_def
|
|
|
|
.fields
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, f)| {
|
2022-10-25 16:15:15 +00:00
|
|
|
let field_name = if variant_def.ctor_kind() == Some(CtorKind::Fn) {
|
2022-03-03 10:15:25 +00:00
|
|
|
// This is a tuple struct
|
|
|
|
tuple_field_name(i)
|
|
|
|
} else {
|
|
|
|
// This is struct with named fields
|
|
|
|
Cow::Borrowed(f.name.as_str())
|
|
|
|
};
|
|
|
|
let field_layout = struct_type_and_layout.field(cx, i);
|
2024-03-02 04:33:46 +00:00
|
|
|
let def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
2023-07-30 03:48:54 +00:00
|
|
|
Some(f.did)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2022-03-03 10:15:25 +00:00
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
|
|
|
owner,
|
|
|
|
&field_name[..],
|
|
|
|
(field_layout.size, field_layout.align.abi),
|
|
|
|
struct_type_and_layout.fields.offset(i),
|
2023-08-23 14:29:23 +00:00
|
|
|
visibility_di_flags(cx, f.did, adt_def.did()),
|
2022-03-03 10:15:25 +00:00
|
|
|
type_di_node(cx, field_layout.ty),
|
2023-07-30 03:48:54 +00:00
|
|
|
def_id,
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
|cx| build_generic_type_param_di_nodes(cx, struct_type),
|
2015-04-29 06:14:37 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
//=-----------------------------------------------------------------------------
|
|
|
|
// Tuples
|
|
|
|
//=-----------------------------------------------------------------------------
|
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
/// Builds the DW_TAG_member debuginfo nodes for the upvars of a closure or coroutine.
|
|
|
|
/// For a coroutine, this will handle upvars shared by all states.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_upvar_field_di_nodes<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2023-10-19 21:46:28 +00:00
|
|
|
closure_or_coroutine_ty: Ty<'tcx>,
|
|
|
|
closure_or_coroutine_di_node: &'ll DIType,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> SmallVec<&'ll DIType> {
|
2023-10-19 21:46:28 +00:00
|
|
|
let (&def_id, up_var_tys) = match closure_or_coroutine_ty.kind() {
|
2023-12-21 01:52:10 +00:00
|
|
|
ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().prefix_tys()),
|
2023-07-25 23:31:21 +00:00
|
|
|
ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()),
|
2024-02-09 15:53:55 +00:00
|
|
|
ty::CoroutineClosure(def_id, args) => (def_id, args.as_coroutine_closure().upvar_tys()),
|
2022-03-03 10:15:25 +00:00
|
|
|
_ => {
|
|
|
|
bug!(
|
2023-10-19 21:46:28 +00:00
|
|
|
"build_upvar_field_di_nodes() called with non-closure-or-coroutine-type: {:?}",
|
|
|
|
closure_or_coroutine_ty
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
};
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2024-11-15 12:53:31 +00:00
|
|
|
assert!(up_var_tys.iter().all(|t| t == cx.tcx.normalize_erasing_regions(cx.typing_env(), t)));
|
2022-03-03 10:15:25 +00:00
|
|
|
|
2022-12-07 17:00:33 +00:00
|
|
|
let capture_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
|
2023-10-19 21:46:28 +00:00
|
|
|
let layout = cx.layout_of(closure_or_coroutine_ty);
|
2022-03-03 10:15:25 +00:00
|
|
|
|
|
|
|
up_var_tys
|
|
|
|
.into_iter()
|
|
|
|
.zip(capture_names.iter())
|
|
|
|
.enumerate()
|
|
|
|
.map(|(index, (up_var_ty, capture_name))| {
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
2023-10-19 21:46:28 +00:00
|
|
|
closure_or_coroutine_di_node,
|
2023-06-18 07:55:04 +00:00
|
|
|
capture_name.as_str(),
|
2022-03-03 10:15:25 +00:00
|
|
|
cx.size_and_align_of(up_var_ty),
|
|
|
|
layout.fields.offset(index),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, up_var_ty),
|
2022-11-18 18:41:53 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
2015-04-29 06:14:37 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Builds the DW_TAG_structure_type debuginfo node for a Rust tuple type.
|
|
|
|
fn build_tuple_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let tuple_type = unique_type_id.expect_ty();
|
|
|
|
let &ty::Tuple(component_types) = tuple_type.kind() else {
|
|
|
|
bug!("build_tuple_type_di_node() called with non-tuple-type: {:?}", tuple_type)
|
|
|
|
};
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let tuple_type_and_layout = cx.layout_of(tuple_type);
|
|
|
|
let type_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
|
|
|
|
|
|
|
|
type_map::build_type_with_children(
|
2015-04-29 06:14:37 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&type_name,
|
2022-11-17 02:31:30 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
size_and_align_of(tuple_type_and_layout),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
// Fields:
|
2022-03-14 16:11:58 +00:00
|
|
|
|cx, tuple_di_node| {
|
2022-03-03 10:15:25 +00:00
|
|
|
component_types
|
|
|
|
.into_iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(index, component_type)| {
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
2022-03-14 16:11:58 +00:00
|
|
|
tuple_di_node,
|
2022-03-03 10:15:25 +00:00
|
|
|
&tuple_field_name(index),
|
|
|
|
cx.size_and_align_of(component_type),
|
|
|
|
tuple_type_and_layout.fields.offset(index),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, component_type),
|
2022-11-18 18:41:53 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
NO_GENERICS,
|
2015-04-29 06:14:37 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-03-14 16:11:58 +00:00
|
|
|
/// Builds the debuginfo node for a closure environment.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_closure_env_di_node<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let closure_env_type = unique_type_id.expect_ty();
|
2024-02-09 15:53:55 +00:00
|
|
|
let &(ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _)) = closure_env_type.kind()
|
|
|
|
else {
|
2022-03-14 16:11:58 +00:00
|
|
|
bug!("build_closure_env_di_node() called with non-closure-type: {:?}", closure_env_type)
|
2022-03-03 10:15:25 +00:00
|
|
|
};
|
|
|
|
let containing_scope = get_namespace_for_item(cx, def_id);
|
|
|
|
let type_name = compute_debuginfo_type_name(cx.tcx, closure_env_type, false);
|
2016-08-22 18:11:22 +00:00
|
|
|
|
2024-03-02 04:33:46 +00:00
|
|
|
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
2023-07-30 04:04:47 +00:00
|
|
|
Some(file_metadata_from_def_id(cx, Some(def_id)))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
|
|
|
cx,
|
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&type_name,
|
2023-07-30 04:04:47 +00:00
|
|
|
def_location,
|
2022-03-03 10:15:25 +00:00
|
|
|
cx.size_and_align_of(closure_env_type),
|
|
|
|
Some(containing_scope),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
// Fields:
|
|
|
|
|cx, owner| build_upvar_field_di_nodes(cx, closure_env_type, owner),
|
2022-03-03 13:43:17 +00:00
|
|
|
NO_GENERICS,
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
2016-08-22 18:11:22 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Build the debuginfo node for a Rust `union` type.
|
|
|
|
fn build_union_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let union_type = unique_type_id.expect_ty();
|
|
|
|
let (union_def_id, variant_def) = match union_type.kind() {
|
2022-03-04 20:28:41 +00:00
|
|
|
ty::Adt(def, _) => (def.did(), def.non_enum_variant()),
|
2022-03-03 10:15:25 +00:00
|
|
|
_ => bug!("build_union_type_di_node on a non-ADT"),
|
2016-08-22 18:11:22 +00:00
|
|
|
};
|
2017-07-07 12:23:38 +00:00
|
|
|
let containing_scope = get_namespace_for_item(cx, union_def_id);
|
2022-03-03 10:15:25 +00:00
|
|
|
let union_ty_and_layout = cx.layout_of(union_type);
|
|
|
|
let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
|
2024-03-02 04:33:46 +00:00
|
|
|
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
2023-07-30 03:48:54 +00:00
|
|
|
Some(file_metadata_from_def_id(cx, Some(union_def_id)))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2016-08-22 18:11:22 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
2016-08-22 18:11:22 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Union,
|
|
|
|
unique_type_id,
|
|
|
|
&type_name,
|
2023-07-30 03:48:54 +00:00
|
|
|
def_location,
|
2022-03-03 10:15:25 +00:00
|
|
|
size_and_align_of(union_ty_and_layout),
|
|
|
|
Some(containing_scope),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
// Fields:
|
|
|
|
|cx, owner| {
|
|
|
|
variant_def
|
|
|
|
.fields
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, f)| {
|
|
|
|
let field_layout = union_ty_and_layout.field(cx, i);
|
2024-03-02 04:33:46 +00:00
|
|
|
let def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
2023-07-30 03:48:54 +00:00
|
|
|
Some(f.did)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2022-03-03 10:15:25 +00:00
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
|
|
|
owner,
|
|
|
|
f.name.as_str(),
|
|
|
|
size_and_align_of(field_layout),
|
|
|
|
Size::ZERO,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, field_layout.ty),
|
2023-07-30 03:48:54 +00:00
|
|
|
def_id,
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
// Generics:
|
|
|
|
|cx| build_generic_type_param_di_nodes(cx, union_type),
|
2016-08-22 18:11:22 +00:00
|
|
|
)
|
|
|
|
}
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2019-05-17 01:20:14 +00:00
|
|
|
/// Computes the type parameters for a type, if any, for the given metadata.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_generic_type_param_di_nodes<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
) -> SmallVec<&'ll DIType> {
|
2023-07-11 21:35:29 +00:00
|
|
|
if let ty::Adt(def, args) = *ty.kind() {
|
|
|
|
if args.types().next().is_some() {
|
2022-03-04 20:28:41 +00:00
|
|
|
let generics = cx.tcx.generics_of(def.did());
|
2018-10-12 13:34:14 +00:00
|
|
|
let names = get_parameter_names(cx, generics);
|
2023-07-11 21:35:29 +00:00
|
|
|
let template_params: SmallVec<_> = iter::zip(args, names)
|
2019-12-24 22:38:22 +00:00
|
|
|
.filter_map(|(kind, name)| {
|
2023-04-19 17:59:30 +00:00
|
|
|
kind.as_type().map(|ty| {
|
2024-11-15 12:53:31 +00:00
|
|
|
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
|
2022-03-14 16:11:58 +00:00
|
|
|
let actual_type_di_node = type_di_node(cx, actual_type);
|
2021-12-15 03:39:23 +00:00
|
|
|
let name = name.as_str();
|
2023-04-19 14:13:22 +00:00
|
|
|
unsafe {
|
2022-03-03 10:15:25 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
|
2019-12-24 22:38:22 +00:00
|
|
|
DIB(cx),
|
|
|
|
None,
|
2024-10-28 07:52:39 +00:00
|
|
|
name.as_c_char_ptr(),
|
2020-03-06 00:00:00 +00:00
|
|
|
name.len(),
|
2022-03-14 16:11:58 +00:00
|
|
|
actual_type_di_node,
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
2023-04-19 14:13:22 +00:00
|
|
|
}
|
|
|
|
})
|
2019-12-24 22:38:22 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2018-10-12 13:34:14 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
return template_params;
|
2018-10-12 13:34:14 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
|
|
|
|
return smallvec![];
|
2018-10-12 13:34:14 +00:00
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
|
|
|
|
let mut names = generics
|
|
|
|
.parent
|
2021-02-25 01:13:42 +00:00
|
|
|
.map_or_else(Vec::new, |def_id| get_parameter_names(cx, cx.tcx.generics_of(def_id)));
|
2024-05-10 00:56:44 +00:00
|
|
|
names.extend(generics.own_params.iter().map(|param| param.name));
|
2018-10-12 13:34:14 +00:00
|
|
|
names
|
2015-04-29 06:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates debug information for the given global variable.
|
|
|
|
///
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Adds the created debuginfo nodes directly to the crate's IR.
|
2024-07-06 12:26:42 +00:00
|
|
|
pub(crate) fn build_global_var_di_node<'ll>(
|
|
|
|
cx: &CodegenCx<'ll, '_>,
|
|
|
|
def_id: DefId,
|
|
|
|
global: &'ll Value,
|
|
|
|
) {
|
2018-01-05 04:58:34 +00:00
|
|
|
if cx.dbg_cx.is_none() {
|
2015-04-29 06:14:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-11 22:20:02 +00:00
|
|
|
// Only create type information if full debuginfo is enabled
|
|
|
|
if cx.sess().opts.debuginfo != DebugInfo::Full {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-05 04:58:34 +00:00
|
|
|
let tcx = cx.tcx;
|
2018-04-12 12:52:09 +00:00
|
|
|
|
2019-05-17 01:20:14 +00:00
|
|
|
// We may want to remove the namespace scope if we're in an extern block (see
|
|
|
|
// https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952).
|
2018-02-19 11:41:10 +00:00
|
|
|
let var_scope = get_namespace_for_item(cx, def_id);
|
2022-11-18 18:41:53 +00:00
|
|
|
let (file_metadata, line_number) = file_metadata_from_def_id(cx, Some(def_id));
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2018-02-19 11:41:10 +00:00
|
|
|
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
|
2024-02-26 18:03:06 +00:00
|
|
|
|
|
|
|
let DefKind::Static { nested, .. } = cx.tcx.def_kind(def_id) else { bug!() };
|
|
|
|
if nested {
|
|
|
|
return;
|
|
|
|
}
|
2024-11-15 12:53:31 +00:00
|
|
|
let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, cx.typing_env());
|
2022-03-03 10:15:25 +00:00
|
|
|
let type_di_node = type_di_node(cx, variable_type);
|
2021-12-14 21:32:21 +00:00
|
|
|
let var_name = tcx.item_name(def_id);
|
|
|
|
let var_name = var_name.as_str();
|
2020-07-10 05:45:05 +00:00
|
|
|
let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
|
2020-03-06 00:00:00 +00:00
|
|
|
// When empty, linkage_name field is omitted,
|
|
|
|
// which is what we want for no_mangle statics
|
2020-05-26 00:00:00 +00:00
|
|
|
let linkage_name = if var_name == linkage_name { "" } else { linkage_name };
|
2016-11-18 16:11:18 +00:00
|
|
|
|
2017-03-02 03:35:25 +00:00
|
|
|
let global_align = cx.align_of(variable_type);
|
2016-11-18 16:11:18 +00:00
|
|
|
|
2015-04-29 06:14:37 +00:00
|
|
|
unsafe {
|
2019-12-24 22:38:22 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateStaticVariable(
|
|
|
|
DIB(cx),
|
|
|
|
Some(var_scope),
|
2024-10-28 07:52:39 +00:00
|
|
|
var_name.as_c_char_ptr(),
|
2020-03-06 00:00:00 +00:00
|
|
|
var_name.len(),
|
2024-10-28 07:52:39 +00:00
|
|
|
linkage_name.as_c_char_ptr(),
|
2020-03-06 00:00:00 +00:00
|
|
|
linkage_name.len(),
|
2019-12-24 22:38:22 +00:00
|
|
|
file_metadata,
|
2021-02-19 20:50:15 +00:00
|
|
|
line_number,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_di_node,
|
2019-12-24 22:38:22 +00:00
|
|
|
is_local_to_unit,
|
|
|
|
global,
|
|
|
|
None,
|
2022-06-07 20:38:35 +00:00
|
|
|
global_align.bits() as u32,
|
2016-11-18 16:11:18 +00:00
|
|
|
);
|
2015-04-29 06:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-25 02:34:31 +00:00
|
|
|
|
2021-10-06 12:26:50 +00:00
|
|
|
/// Generates LLVM debuginfo for a vtable.
|
2022-01-25 13:34:34 +00:00
|
|
|
///
|
|
|
|
/// The vtable type looks like a struct with a field for each function pointer and super-trait
|
|
|
|
/// pointer it contains (plus the `size` and `align` fields).
|
|
|
|
///
|
|
|
|
/// Except for `size`, `align`, and `drop_in_place`, the field names don't try to mirror
|
|
|
|
/// the name of the method they implement. This can be implemented in the future once there
|
|
|
|
/// is a proper disambiguation scheme for dealing with methods from different traits that have
|
|
|
|
/// the same name.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_vtable_type_di_node<'ll, 'tcx>(
|
2021-10-06 12:26:50 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
|
|
|
) -> &'ll DIType {
|
|
|
|
let tcx = cx.tcx;
|
|
|
|
|
|
|
|
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
|
|
|
|
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
|
|
|
|
let trait_ref = tcx.erase_regions(trait_ref);
|
|
|
|
|
|
|
|
tcx.vtable_entries(trait_ref)
|
|
|
|
} else {
|
2022-05-27 03:22:28 +00:00
|
|
|
TyCtxt::COMMON_VTABLE_ENTRIES
|
2021-10-06 12:26:50 +00:00
|
|
|
};
|
|
|
|
|
2022-01-25 13:34:34 +00:00
|
|
|
// All function pointers are described as opaque pointers. This could be improved in the future
|
|
|
|
// by describing them as actual function pointers.
|
2023-07-05 19:13:26 +00:00
|
|
|
let void_pointer_ty = Ty::new_imm_ptr(tcx, tcx.types.unit);
|
2022-03-03 10:15:25 +00:00
|
|
|
let void_pointer_type_di_node = type_di_node(cx, void_pointer_ty);
|
|
|
|
let usize_di_node = type_di_node(cx, tcx.types.usize);
|
2022-01-25 13:34:34 +00:00
|
|
|
let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty);
|
|
|
|
// If `usize` is not pointer-sized and -aligned then the size and alignment computations
|
|
|
|
// for the vtable as a whole would be wrong. Let's make sure this holds even on weird
|
|
|
|
// platforms.
|
|
|
|
assert_eq!(cx.size_and_align_of(tcx.types.usize), (pointer_size, pointer_align));
|
|
|
|
|
|
|
|
let vtable_type_name =
|
|
|
|
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type);
|
2022-02-04 12:19:55 +00:00
|
|
|
let unique_type_id = UniqueTypeId::for_vtable_ty(tcx, ty, poly_trait_ref);
|
2022-01-25 13:34:34 +00:00
|
|
|
let size = pointer_size * vtable_entries.len() as u64;
|
|
|
|
|
|
|
|
// This gets mapped to a DW_AT_containing_type attribute which allows GDB to correlate
|
|
|
|
// the vtable to the type it is for.
|
2022-03-03 10:15:25 +00:00
|
|
|
let vtable_holder = type_di_node(cx, ty);
|
2022-01-25 13:34:34 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
build_type_with_children(
|
2022-01-25 13:34:34 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
2022-07-19 23:57:44 +00:00
|
|
|
Stub::VTableTy { vtable_holder },
|
2022-03-03 10:15:25 +00:00
|
|
|
unique_type_id,
|
|
|
|
&vtable_type_name,
|
2022-11-17 02:31:30 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
(size, pointer_align),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagArtificial,
|
|
|
|
),
|
|
|
|
|cx, vtable_type_di_node| {
|
|
|
|
vtable_entries
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.filter_map(|(index, vtable_entry)| {
|
|
|
|
let (field_name, field_type_di_node) = match vtable_entry {
|
|
|
|
ty::VtblEntry::MetadataDropInPlace => {
|
|
|
|
("drop_in_place".to_string(), void_pointer_type_di_node)
|
|
|
|
}
|
|
|
|
ty::VtblEntry::Method(_) => {
|
|
|
|
// Note: This code does not try to give a proper name to each method
|
|
|
|
// because their might be multiple methods with the same name
|
|
|
|
// (coming from different traits).
|
2023-07-25 21:04:01 +00:00
|
|
|
(format!("__method{index}"), void_pointer_type_di_node)
|
2022-03-03 10:15:25 +00:00
|
|
|
}
|
|
|
|
ty::VtblEntry::TraitVPtr(_) => {
|
2023-07-25 21:04:01 +00:00
|
|
|
(format!("__super_trait_ptr{index}"), void_pointer_type_di_node)
|
2022-03-03 10:15:25 +00:00
|
|
|
}
|
|
|
|
ty::VtblEntry::MetadataAlign => ("align".to_string(), usize_di_node),
|
|
|
|
ty::VtblEntry::MetadataSize => ("size".to_string(), usize_di_node),
|
|
|
|
ty::VtblEntry::Vacant => return None,
|
|
|
|
};
|
2022-01-25 13:34:34 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let field_offset = pointer_size * index as u64;
|
2021-10-06 12:26:50 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
Some(build_field_di_node(
|
|
|
|
cx,
|
|
|
|
vtable_type_di_node,
|
|
|
|
&field_name,
|
|
|
|
(pointer_size, pointer_align),
|
|
|
|
field_offset,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
field_type_di_node,
|
2022-11-18 18:41:53 +00:00
|
|
|
None,
|
2022-03-03 10:15:25 +00:00
|
|
|
))
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
NO_GENERICS,
|
|
|
|
)
|
|
|
|
.di_node
|
2021-10-06 12:26:50 +00:00
|
|
|
}
|
|
|
|
|
2024-03-30 12:01:57 +00:00
|
|
|
pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
2022-04-21 13:02:54 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
|
|
|
|
vtable: &'ll Value,
|
|
|
|
) {
|
2024-03-30 12:01:57 +00:00
|
|
|
// FIXME(flip1995): The virtual function elimination optimization only works with full LTO in
|
|
|
|
// LLVM at the moment.
|
|
|
|
if !cx.sess().opts.unstable_opts.virtual_function_elimination || cx.sess().lto() != Lto::Fat {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-21 13:02:54 +00:00
|
|
|
enum VCallVisibility {
|
|
|
|
Public = 0,
|
|
|
|
LinkageUnit = 1,
|
|
|
|
TranslationUnit = 2,
|
|
|
|
}
|
|
|
|
|
|
|
|
let Some(trait_ref) = trait_ref else { return };
|
|
|
|
|
|
|
|
let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
|
|
|
|
let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
|
|
|
|
let trait_def_id = trait_ref_self.def_id();
|
|
|
|
let trait_vis = cx.tcx.visibility(trait_def_id);
|
|
|
|
|
Introduce a minimum CGU size in non-incremental builds.
Because tiny CGUs make compilation less efficient *and* result in worse
generated code.
We don't do this when the number of CGUs is explicitly given, because
there are times when the requested number is very important, as
described in some comments within the commit. So the commit also
introduces a `CodegenUnits` type that distinguishes between default
values and user-specified values.
This change has a roughly neutral effect on walltimes across the
rustc-perf benchmarks; there are some speedups and some slowdowns. But
it has significant wins for most other metrics on numerous benchmarks,
including instruction counts, cycles, binary size, and max-rss. It also
reduces parallelism, which is good for reducing jobserver competition
when multiple rustc processes are running at the same time. It's smaller
benchmarks that benefit the most; larger benchmarks already have CGUs
that are all larger than the minimum size.
Here are some example before/after CGU sizes for opt builds.
- html5ever
- CGUs: 16, mean size: 1196.1, sizes: [3908, 2992, 1706, 1652, 1572,
1136, 1045, 948, 946, 938, 579, 471, 443, 327, 286, 189]
- CGUs: 4, mean size: 4396.0, sizes: [6706, 3908, 3490, 3480]
- libc
- CGUs: 12, mean size: 35.3, sizes: [163, 93, 58, 53, 37, 8, 2 (x6)]
- CGUs: 1, mean size: 424.0, sizes: [424]
- tt-muncher
- CGUs: 5, mean size: 1819.4, sizes: [8508, 350, 198, 34, 7]
- CGUs: 1, mean size: 9075.0, sizes: [9075]
Note that CGUs of size 100,000+ aren't unusual in larger programs.
2023-06-09 04:39:13 +00:00
|
|
|
let cgus = cx.sess().codegen_units().as_usize();
|
2022-04-21 13:02:54 +00:00
|
|
|
let single_cgu = cgus == 1;
|
|
|
|
|
|
|
|
let lto = cx.sess().lto();
|
|
|
|
|
|
|
|
// Since LLVM requires full LTO for the virtual function elimination optimization to apply,
|
|
|
|
// only the `Lto::Fat` cases are relevant currently.
|
|
|
|
let vcall_visibility = match (lto, trait_vis, single_cgu) {
|
|
|
|
// If there is not LTO and the visibility in public, we have to assume that the vtable can
|
|
|
|
// be seen from anywhere. With multiple CGUs, the vtable is quasi-public.
|
|
|
|
(Lto::No | Lto::ThinLocal, Visibility::Public, _)
|
2022-08-27 15:36:57 +00:00
|
|
|
| (Lto::No, Visibility::Restricted(_), false) => VCallVisibility::Public,
|
2022-04-21 13:02:54 +00:00
|
|
|
// With LTO and a quasi-public visibility, the usages of the functions of the vtable are
|
|
|
|
// all known by the `LinkageUnit`.
|
|
|
|
// FIXME: LLVM only supports this optimization for `Lto::Fat` currently. Once it also
|
|
|
|
// supports `Lto::Thin` the `VCallVisibility` may have to be adjusted for those.
|
|
|
|
(Lto::Fat | Lto::Thin, Visibility::Public, _)
|
2022-08-27 15:36:57 +00:00
|
|
|
| (Lto::ThinLocal | Lto::Thin | Lto::Fat, Visibility::Restricted(_), false) => {
|
|
|
|
VCallVisibility::LinkageUnit
|
|
|
|
}
|
2022-04-21 13:02:54 +00:00
|
|
|
// If there is only one CGU, private vtables can only be seen by that CGU/translation unit
|
|
|
|
// and therefore we know of all usages of functions in the vtable.
|
2022-08-27 15:36:57 +00:00
|
|
|
(_, Visibility::Restricted(_), true) => VCallVisibility::TranslationUnit,
|
2022-04-21 13:02:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);
|
|
|
|
|
|
|
|
unsafe {
|
2024-09-19 01:39:28 +00:00
|
|
|
let typeid = llvm::LLVMMDStringInContext2(
|
2022-04-21 13:02:54 +00:00
|
|
|
cx.llcx,
|
|
|
|
trait_ref_typeid.as_ptr() as *const c_char,
|
2024-09-19 01:39:28 +00:00
|
|
|
trait_ref_typeid.as_bytes().len(),
|
2022-04-21 13:02:54 +00:00
|
|
|
);
|
2024-09-19 01:39:28 +00:00
|
|
|
let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
|
2022-04-21 13:02:54 +00:00
|
|
|
llvm::LLVMRustGlobalAddMetadata(
|
|
|
|
vtable,
|
|
|
|
llvm::MD_type as c_uint,
|
2024-09-19 01:39:28 +00:00
|
|
|
llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()),
|
2022-04-21 13:02:54 +00:00
|
|
|
);
|
|
|
|
let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64));
|
|
|
|
let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1);
|
|
|
|
llvm::LLVMGlobalSetMetadata(
|
|
|
|
vtable,
|
|
|
|
llvm::MetadataType::MD_vcall_visibility as c_uint,
|
|
|
|
vcall_visibility_metadata,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-20 13:47:22 +00:00
|
|
|
/// Creates debug information for the given vtable, which is for the
|
|
|
|
/// given type.
|
|
|
|
///
|
|
|
|
/// Adds the created metadata nodes directly to the crate's IR.
|
2024-07-06 12:26:42 +00:00
|
|
|
pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
|
2021-10-06 12:26:50 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
|
|
|
vtable: &'ll Value,
|
|
|
|
) {
|
2018-09-20 13:47:22 +00:00
|
|
|
if cx.dbg_cx.is_none() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-11 22:20:02 +00:00
|
|
|
// Only create type information if full debuginfo is enabled
|
|
|
|
if cx.sess().opts.debuginfo != DebugInfo::Full {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-27 15:29:04 +00:00
|
|
|
// When full debuginfo is enabled, we want to try and prevent vtables from being
|
|
|
|
// merged. Otherwise debuggers will have a hard time mapping from dyn pointer
|
|
|
|
// to concrete type.
|
|
|
|
llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No);
|
|
|
|
|
2022-01-25 13:34:34 +00:00
|
|
|
let vtable_name =
|
|
|
|
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
|
2022-03-03 10:15:25 +00:00
|
|
|
let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref);
|
2022-01-25 13:34:34 +00:00
|
|
|
let linkage_name = "";
|
2018-09-20 13:47:22 +00:00
|
|
|
|
|
|
|
unsafe {
|
2019-12-24 22:38:22 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateStaticVariable(
|
|
|
|
DIB(cx),
|
|
|
|
NO_SCOPE_METADATA,
|
2024-10-28 07:52:39 +00:00
|
|
|
vtable_name.as_c_char_ptr(),
|
2021-10-06 12:26:50 +00:00
|
|
|
vtable_name.len(),
|
2024-10-28 07:52:39 +00:00
|
|
|
linkage_name.as_c_char_ptr(),
|
2020-03-06 00:00:00 +00:00
|
|
|
linkage_name.len(),
|
2019-12-24 22:38:22 +00:00
|
|
|
unknown_file_metadata(cx),
|
|
|
|
UNKNOWN_LINE_NUMBER,
|
2022-03-03 10:15:25 +00:00
|
|
|
vtable_type_di_node,
|
2019-12-24 22:38:22 +00:00
|
|
|
true,
|
|
|
|
vtable,
|
|
|
|
None,
|
|
|
|
0,
|
|
|
|
);
|
2018-09-20 13:47:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-17 01:20:14 +00:00
|
|
|
/// Creates an "extension" of an existing `DIScope` into another file.
|
2024-07-06 12:26:42 +00:00
|
|
|
pub(crate) fn extend_scope_to_file<'ll>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, '_>,
|
|
|
|
scope_metadata: &'ll DIScope,
|
2020-02-10 01:03:24 +00:00
|
|
|
file: &SourceFile,
|
2018-07-04 13:36:49 +00:00
|
|
|
) -> &'ll DILexicalBlock {
|
2020-02-10 01:03:24 +00:00
|
|
|
let file_metadata = file_metadata(cx, file);
|
2019-12-24 22:38:22 +00:00
|
|
|
unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) }
|
2016-08-26 16:23:42 +00:00
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
|
2024-07-06 12:26:42 +00:00
|
|
|
fn tuple_field_name(field_index: usize) -> Cow<'static, str> {
|
2022-03-03 10:15:25 +00:00
|
|
|
const TUPLE_FIELD_NAMES: [&'static str; 16] = [
|
|
|
|
"__0", "__1", "__2", "__3", "__4", "__5", "__6", "__7", "__8", "__9", "__10", "__11",
|
|
|
|
"__12", "__13", "__14", "__15",
|
|
|
|
];
|
|
|
|
TUPLE_FIELD_NAMES
|
|
|
|
.get(field_index)
|
|
|
|
.map(|s| Cow::from(*s))
|
2023-07-25 21:04:01 +00:00
|
|
|
.unwrap_or_else(|| Cow::from(format!("__{field_index}")))
|
2022-03-03 10:15:25 +00:00
|
|
|
}
|
2022-11-18 18:41:53 +00:00
|
|
|
|
2022-11-23 05:02:00 +00:00
|
|
|
pub(crate) type DefinitionLocation<'ll> = (&'ll DIFile, c_uint);
|
|
|
|
|
2022-11-18 18:41:53 +00:00
|
|
|
pub(crate) fn file_metadata_from_def_id<'ll>(
|
|
|
|
cx: &CodegenCx<'ll, '_>,
|
|
|
|
def_id: Option<DefId>,
|
2022-11-23 05:02:00 +00:00
|
|
|
) -> DefinitionLocation<'ll> {
|
2022-11-18 18:41:53 +00:00
|
|
|
if let Some(def_id) = def_id
|
|
|
|
&& let span = hygiene::walk_chain_collapsed(cx.tcx.def_span(def_id), DUMMY_SP)
|
|
|
|
&& !span.is_dummy()
|
|
|
|
{
|
|
|
|
let loc = cx.lookup_debug_loc(span.lo());
|
|
|
|
(file_metadata(cx, &loc.file), loc.line)
|
|
|
|
} else {
|
|
|
|
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
|
|
|
|
}
|
|
|
|
}
|