Auto merge of #104342 - mweber15:add_file_location_to_more_types, r=wesleywiser

Require `type_map::stub` callers to supply file information

This change attaches file information (`DIFile` reference and line number) to struct debug info nodes.

Before:

```
; foo.ll
...
!5 = !DIFile(filename: "<unknown>", directory: "")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !5, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "4cb373851db92e732c4cb5651b886dd0")
...
```

After:

```
; foo.ll
...
!3 = !DIFile(filename: "foo.rs", directory: "/home/matt/src/rust98678", checksumkind: CSK_SHA1, checksum: "bcb9f08512c8f3b8181ef4726012bc6807bc9be4")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !3, line: 3, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "9e5968c7af39c148acb253912b7f409f")
...
```

Fixes #98678

r? `@wesleywiser`
This commit is contained in:
bors 2024-12-03 12:49:57 +00:00
commit 8575f8f91b
12 changed files with 350 additions and 27 deletions

View File

@ -203,6 +203,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&ptr_type_debuginfo_name,
None,
cx.size_and_align_of(ptr_type),
NO_SCOPE_METADATA,
DIFlags::FlagZero,
@ -259,6 +260,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
layout.fields.offset(abi::WIDE_PTR_ADDR),
DIFlags::FlagZero,
data_ptr_type_di_node,
None,
),
build_field_di_node(
cx,
@ -268,6 +270,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
layout.fields.offset(abi::WIDE_PTR_EXTRA),
DIFlags::FlagZero,
type_di_node(cx, extra_field.ty),
None,
),
]
},
@ -369,6 +372,7 @@ fn build_dyn_type_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&type_name,
None,
cx.size_and_align_of(dyn_type),
NO_SCOPE_METADATA,
DIFlags::FlagZero,
@ -722,6 +726,14 @@ fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreation
// `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;
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
};
type_map::build_type_with_children(
cx,
type_map::stub(
@ -729,12 +741,21 @@ fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreation
Stub::Struct,
UniqueTypeId::for_ty(cx.tcx, float_ty),
"f16",
def_location,
cx.size_and_align_of(float_ty),
NO_SCOPE_METADATA,
DIFlags::FlagZero,
),
// Fields:
|cx, float_di_node| {
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
};
smallvec![build_field_di_node(
cx,
float_di_node,
@ -743,6 +764,7 @@ fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreation
Size::ZERO,
DIFlags::FlagZero,
type_di_node(cx, bits_ty),
def_id,
)]
},
NO_GENERICS,
@ -839,6 +861,7 @@ fn build_foreign_type_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&compute_debuginfo_type_name(cx.tcx, t, false),
None,
cx.size_and_align_of(t),
Some(get_namespace_for_item(cx, def_id)),
DIFlags::FlagZero,
@ -989,15 +1012,22 @@ fn build_field_di_node<'ll, 'tcx>(
offset: Size,
flags: DIFlags,
type_di_node: &'ll DIType,
def_id: Option<DefId>,
) -> &'ll DIType {
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)
};
unsafe {
llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx),
owner,
name.as_c_char_ptr(),
name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
file_metadata,
line_number,
size_and_align.0.bits(),
size_and_align.1.bits() as u32,
offset.bits(),
@ -1041,6 +1071,11 @@ fn build_struct_type_di_node<'ll, 'tcx>(
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();
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(adt_def.did())))
} else {
None
};
type_map::build_type_with_children(
cx,
@ -1049,6 +1084,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&compute_debuginfo_type_name(cx.tcx, struct_type, false),
def_location,
size_and_align_of(struct_type_and_layout),
Some(containing_scope),
visibility_di_flags(cx, adt_def.did(), adt_def.did()),
@ -1068,6 +1104,11 @@ fn build_struct_type_di_node<'ll, 'tcx>(
Cow::Borrowed(f.name.as_str())
};
let field_layout = struct_type_and_layout.field(cx, i);
let def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(f.did)
} else {
None
};
build_field_di_node(
cx,
owner,
@ -1076,6 +1117,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
struct_type_and_layout.fields.offset(i),
visibility_di_flags(cx, f.did, adt_def.did()),
type_di_node(cx, field_layout.ty),
def_id,
)
})
.collect()
@ -1125,6 +1167,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
layout.fields.offset(index),
DIFlags::FlagZero,
type_di_node(cx, up_var_ty),
None,
)
})
.collect()
@ -1150,6 +1193,7 @@ fn build_tuple_type_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&type_name,
None,
size_and_align_of(tuple_type_and_layout),
NO_SCOPE_METADATA,
DIFlags::FlagZero,
@ -1168,6 +1212,7 @@ fn build_tuple_type_di_node<'ll, 'tcx>(
tuple_type_and_layout.fields.offset(index),
DIFlags::FlagZero,
type_di_node(cx, component_type),
None,
)
})
.collect()
@ -1189,6 +1234,12 @@ fn build_closure_env_di_node<'ll, 'tcx>(
let containing_scope = get_namespace_for_item(cx, def_id);
let type_name = compute_debuginfo_type_name(cx.tcx, closure_env_type, false);
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(def_id)))
} else {
None
};
type_map::build_type_with_children(
cx,
type_map::stub(
@ -1196,6 +1247,7 @@ fn build_closure_env_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&type_name,
def_location,
cx.size_and_align_of(closure_env_type),
Some(containing_scope),
DIFlags::FlagZero,
@ -1219,6 +1271,11 @@ fn build_union_type_di_node<'ll, 'tcx>(
let containing_scope = get_namespace_for_item(cx, union_def_id);
let union_ty_and_layout = cx.layout_of(union_type);
let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(union_def_id)))
} else {
None
};
type_map::build_type_with_children(
cx,
@ -1227,6 +1284,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
Stub::Union,
unique_type_id,
&type_name,
def_location,
size_and_align_of(union_ty_and_layout),
Some(containing_scope),
DIFlags::FlagZero,
@ -1239,6 +1297,11 @@ fn build_union_type_di_node<'ll, 'tcx>(
.enumerate()
.map(|(i, f)| {
let field_layout = union_ty_and_layout.field(cx, i);
let def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(f.did)
} else {
None
};
build_field_di_node(
cx,
owner,
@ -1247,6 +1310,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
Size::ZERO,
DIFlags::FlagZero,
type_di_node(cx, field_layout.ty),
def_id,
)
})
.collect()
@ -1321,14 +1385,7 @@ pub(crate) fn build_global_var_di_node<'ll>(
// 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).
let var_scope = get_namespace_for_item(cx, def_id);
let span = hygiene::walk_chain_collapsed(tcx.def_span(def_id), DUMMY_SP);
let (file_metadata, line_number) = if !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)
};
let (file_metadata, line_number) = file_metadata_from_def_id(cx, Some(def_id));
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
@ -1418,6 +1475,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
Stub::VTableTy { vtable_holder },
unique_type_id,
&vtable_type_name,
None,
(size, pointer_align),
NO_SCOPE_METADATA,
DIFlags::FlagArtificial,
@ -1455,6 +1513,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
field_offset,
DIFlags::FlagZero,
field_type_di_node,
None,
))
})
.collect()
@ -1606,3 +1665,20 @@ fn tuple_field_name(field_index: usize) -> Cow<'static, str> {
.map(|s| Cow::from(*s))
.unwrap_or_else(|| Cow::from(format!("__{field_index}")))
}
pub(crate) type DefinitionLocation<'ll> = (&'ll DIFile, c_uint);
pub(crate) fn file_metadata_from_def_id<'ll>(
cx: &CodegenCx<'ll, '_>,
def_id: Option<DefId>,
) -> DefinitionLocation<'ll> {
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)
}
}

View File

@ -4,7 +4,7 @@ use libc::c_uint;
use rustc_abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_codegen_ssa::traits::ConstCodegenMethods;
use rustc_codegen_ssa::traits::{ConstCodegenMethods, MiscCodegenMethods};
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
@ -16,8 +16,8 @@ use crate::debuginfo::metadata::enums::DiscrResult;
use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
use crate::debuginfo::metadata::{
DINodeCreationResult, NO_GENERICS, NO_SCOPE_METADATA, SmallVec, UNKNOWN_LINE_NUMBER,
build_field_di_node, file_metadata, size_and_align_of, type_di_node, unknown_file_metadata,
visibility_di_flags,
build_field_di_node, file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
unknown_file_metadata, visibility_di_flags,
};
use crate::debuginfo::utils::DIB;
use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
@ -192,6 +192,12 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(enum_adt_def.did())))
} else {
None
};
type_map::build_type_with_children(
cx,
type_map::stub(
@ -199,6 +205,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
type_map::Stub::Union,
unique_type_id,
&enum_type_name,
def_location,
cx.size_and_align_of(enum_type),
NO_SCOPE_METADATA,
visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did()),
@ -262,6 +269,14 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
unique_type_id: UniqueTypeId<'tcx>,
) -> DINodeCreationResult<'ll> {
let coroutine_type = unique_type_id.expect_ty();
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
let &ty::Coroutine(coroutine_def_id, _) = coroutine_type.kind() else {
bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type)
};
Some(file_metadata_from_def_id(cx, Some(coroutine_def_id)))
} else {
None
};
let coroutine_type_and_layout = cx.layout_of(coroutine_type);
let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
@ -274,6 +289,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
type_map::Stub::Union,
unique_type_id,
&coroutine_type_name,
def_location,
size_and_align_of(coroutine_type_and_layout),
NO_SCOPE_METADATA,
DIFlags::FlagZero,
@ -321,6 +337,12 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
let tag_base_type_di_node = type_di_node(cx, tag_base_type);
let tag_base_type_align = cx.align_of(tag_base_type);
let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(enum_adt_def.did())
} else {
None
};
let variant_names_type_di_node = build_variant_names_type_di_node(
cx,
enum_type_di_node,
@ -328,6 +350,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
variant_index,
Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
)),
enum_adt_def_id,
);
let variant_struct_type_wrapper_di_node = build_variant_struct_wrapper_type_di_node(
@ -341,6 +364,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
tag_base_type_di_node,
tag_base_type,
DiscrResult::NoDiscriminant,
None,
);
smallvec![
@ -354,6 +378,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
Size::ZERO,
visibility_flags,
variant_struct_type_wrapper_di_node,
None,
),
unsafe {
llvm::LLVMRustDIBuilderCreateStaticMemberType(
@ -383,6 +408,12 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
) -> SmallVec<&'ll DIType> {
let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(enum_adt_def.did())
} else {
None
};
let variant_names_type_di_node = build_variant_names_type_di_node(
cx,
enum_type_di_node,
@ -390,6 +421,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
(variant_index, variant_name)
}),
enum_adt_def_id,
);
let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
@ -447,6 +479,7 @@ fn build_variant_names_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
containing_scope: &'ll DIType,
variants: impl Iterator<Item = (VariantIdx, Cow<'tcx, str>)>,
enum_def_id: Option<rustc_span::def_id::DefId>,
) -> &'ll DIType {
// Create an enumerator for each variant.
super::build_enumeration_type_di_node(
@ -454,6 +487,7 @@ fn build_variant_names_type_di_node<'ll, 'tcx>(
"VariantNames",
variant_names_enum_base_type(cx),
variants.map(|(variant_index, variant_name)| (variant_name, variant_index.as_u32().into())),
enum_def_id,
containing_scope,
)
}
@ -469,6 +503,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
tag_base_type_di_node: &'ll DIType,
tag_base_type: Ty<'tcx>,
discr: DiscrResult,
source_info: Option<(&'ll DIFile, c_uint)>,
) -> &'ll DIType {
type_map::build_type_with_children(
cx,
@ -481,6 +516,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
variant_index,
),
&variant_struct_wrapper_type_name(variant_index),
source_info,
// NOTE: We use size and align of enum_type, not from variant_layout:
size_and_align_of(enum_or_coroutine_type_and_layout),
Some(enum_or_coroutine_type_di_node),
@ -530,6 +566,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
Size::ZERO,
DIFlags::FlagZero,
variant_struct_type_di_node,
None,
));
let build_assoc_const =
@ -684,6 +721,11 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
variant_range
.clone()
.map(|variant_index| (variant_index, CoroutineArgs::variant_name(variant_index))),
if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(coroutine_def_id)
} else {
None
},
);
let discriminants: IndexVec<VariantIdx, DiscrResult> = {
@ -776,6 +818,11 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
tag_base_type_di_node,
tag_base_type,
variant_member_info.discr,
if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
variant_member_info.source_info
} else {
None
},
);
// We use LLVMRustDIBuilderCreateMemberType() member type directly because
@ -831,6 +878,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
lo_offset,
di_flags,
type_di_node,
None,
));
unions_fields.push(build_field_di_node(
@ -841,6 +889,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
hi_offset,
DIFlags::FlagZero,
type_di_node,
None,
));
} else {
unions_fields.push(build_field_di_node(
@ -851,6 +900,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
enum_type_and_layout.fields.offset(tag_field),
di_flags,
tag_base_type_di_node,
None,
));
}

View File

@ -3,6 +3,7 @@ use std::borrow::Cow;
use rustc_abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_like_debuginfo};
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_codegen_ssa::traits::MiscCodegenMethods;
use rustc_hir::def::CtorKind;
use rustc_index::IndexSlice;
use rustc_middle::bug;
@ -16,8 +17,8 @@ use super::{SmallVec, size_and_align_of};
use crate::common::{AsCCharPtr, CodegenCx};
use crate::debuginfo::metadata::type_map::{self, Stub};
use crate::debuginfo::metadata::{
UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes, type_di_node,
unknown_file_metadata,
UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes,
file_metadata_from_def_id, type_di_node, unknown_file_metadata,
};
use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
use crate::llvm::debuginfo::{DIFlags, DIType};
@ -68,6 +69,11 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
enum_type_and_layout: TyAndLayout<'tcx>,
) -> DINodeCreationResult<'ll> {
let containing_scope = get_namespace_for_item(cx, enum_adt_def.did());
let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(enum_adt_def.did())
} else {
None
};
DINodeCreationResult {
di_node: build_enumeration_type_di_node(
cx,
@ -77,6 +83,7 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
(name, discr.val)
}),
enum_adt_def_id,
containing_scope,
),
already_stored_in_typemap: false,
@ -92,6 +99,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
type_name: &str,
base_type: Ty<'tcx>,
enumerators: impl Iterator<Item = (Cow<'tcx, str>, u128)>,
def_id: Option<rustc_span::def_id::DefId>,
containing_scope: &'ll DIType,
) -> &'ll DIType {
let is_unsigned = match base_type.kind() {
@ -115,14 +123,21 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
})
.collect();
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)
};
unsafe {
llvm::LLVMRustDIBuilderCreateEnumerationType(
DIB(cx),
containing_scope,
type_name.as_c_char_ptr(),
type_name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
file_metadata,
line_number,
size.bits(),
align.bits() as u32,
create_DIArray(DIB(cx), &enumerator_di_nodes[..]),
@ -193,6 +208,12 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
) -> &'ll DIType {
assert_eq!(variant_layout.ty, enum_type_and_layout.ty);
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(variant_def.def_id)))
} else {
None
};
type_map::build_type_with_children(
cx,
type_map::stub(
@ -204,6 +225,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
variant_index,
),
variant_def.name.as_str(),
def_location,
// NOTE: We use size and align of enum_type, not from variant_layout:
size_and_align_of(enum_type_and_layout),
Some(enum_type_di_node),
@ -231,6 +253,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
variant_layout.fields.offset(field_index),
di_flags,
type_di_node(cx, field_layout.ty),
None,
)
})
.collect::<SmallVec<_>>()
@ -286,6 +309,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&variant_name,
None,
size_and_align_of(coroutine_type_and_layout),
Some(coroutine_type_di_node),
DIFlags::FlagZero,
@ -312,6 +336,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
variant_layout.fields.offset(field_index),
DIFlags::FlagZero,
type_di_node(cx, field_type),
None,
)
})
.collect();
@ -331,6 +356,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
coroutine_type_and_layout.fields.offset(index),
DIFlags::FlagZero,
type_di_node(cx, upvar_ty),
None,
)
})
.collect();

View File

@ -4,7 +4,7 @@ use libc::c_uint;
use rustc_abi::{Size, TagEncoding, VariantIdx, Variants};
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_codegen_ssa::traits::ConstCodegenMethods;
use rustc_codegen_ssa::traits::{ConstCodegenMethods, MiscCodegenMethods};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self};
@ -14,7 +14,8 @@ use crate::common::{AsCCharPtr, CodegenCx};
use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
use crate::debuginfo::metadata::{
DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, file_metadata,
size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags,
file_metadata_from_def_id, size_and_align_of, type_di_node, unknown_file_metadata,
visibility_di_flags,
};
use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
@ -55,6 +56,12 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(enum_adt_def.did())))
} else {
None
};
type_map::build_type_with_children(
cx,
type_map::stub(
@ -62,6 +69,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&enum_type_name,
def_location,
size_and_align_of(enum_type_and_layout),
Some(containing_scope),
visibility_flags,
@ -84,14 +92,27 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
enum_type_and_layout.for_variant(cx, variant_index),
visibility_flags,
),
source_info: None,
source_info: if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(
cx,
Some(enum_adt_def.variant(variant_index).def_id),
))
} else {
None
},
})
.collect();
let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(enum_adt_def.did())
} else {
None
};
smallvec![build_enum_variant_part_di_node(
cx,
enum_type_and_layout,
enum_type_di_node,
enum_adt_def_id,
&variant_member_infos[..],
)]
},
@ -134,6 +155,12 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(file_metadata_from_def_id(cx, Some(coroutine_def_id)))
} else {
None
};
type_map::build_type_with_children(
cx,
type_map::stub(
@ -141,6 +168,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
Stub::Struct,
unique_type_id,
&coroutine_type_name,
def_location,
size_and_align_of(coroutine_type_and_layout),
Some(containing_scope),
DIFlags::FlagZero,
@ -197,10 +225,16 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
})
.collect();
let coroutine_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
Some(coroutine_def_id)
} else {
None
};
smallvec![build_enum_variant_part_di_node(
cx,
coroutine_type_and_layout,
coroutine_type_di_node,
coroutine_def_id,
&variant_struct_type_di_nodes[..],
)]
},
@ -228,6 +262,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
enum_type_and_layout: TyAndLayout<'tcx>,
enum_type_di_node: &'ll DIType,
enum_type_def_id: Option<rustc_span::def_id::DefId>,
variant_member_infos: &[VariantMemberInfo<'_, 'll>],
) -> &'ll DIType {
let tag_member_di_node =
@ -236,6 +271,13 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>(
let variant_part_unique_type_id =
UniqueTypeId::for_enum_variant_part(cx.tcx, enum_type_and_layout.ty);
let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
{
file_metadata_from_def_id(cx, enum_type_def_id)
} else {
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
};
let stub = StubInfo::new(
cx,
variant_part_unique_type_id,
@ -246,8 +288,8 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>(
enum_type_di_node,
variant_part_name.as_c_char_ptr(),
variant_part_name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
file_metadata,
line_number,
enum_type_and_layout.size.bits(),
enum_type_and_layout.align.abi.bits() as u32,
DIFlags::FlagZero,

View File

@ -8,7 +8,7 @@ use rustc_macros::HashStable;
use rustc_middle::bug;
use rustc_middle::ty::{self, PolyExistentialTraitRef, Ty, TyCtxt};
use super::{SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
use crate::common::{AsCCharPtr, CodegenCx};
use crate::debuginfo::utils::{DIB, create_DIArray, debug_context};
use crate::llvm::debuginfo::{DIFlags, DIScope, DIType};
@ -186,6 +186,7 @@ pub(super) fn stub<'ll, 'tcx>(
kind: Stub<'ll>,
unique_type_id: UniqueTypeId<'tcx>,
name: &str,
def_location: Option<DefinitionLocation<'ll>>,
(size, align): (Size, Align),
containing_scope: Option<&'ll DIScope>,
flags: DIFlags,
@ -193,6 +194,12 @@ pub(super) fn stub<'ll, 'tcx>(
let empty_array = create_DIArray(DIB(cx), &[]);
let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx);
let (file_metadata, line_number) = if let Some(def_location) = def_location {
(def_location.0, def_location.1)
} else {
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
};
let metadata = match kind {
Stub::Struct | Stub::VTableTy { .. } => {
let vtable_holder = match kind {
@ -205,8 +212,8 @@ pub(super) fn stub<'ll, 'tcx>(
containing_scope,
name.as_c_char_ptr(),
name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
file_metadata,
line_number,
size.bits(),
align.bits() as u32,
flags,
@ -225,8 +232,8 @@ pub(super) fn stub<'ll, 'tcx>(
containing_scope,
name.as_c_char_ptr(),
name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
file_metadata,
line_number,
size.bits(),
align.bits() as u32,
flags,

View File

@ -771,6 +771,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
tracked!(debug_info_for_profiling, true);
tracked!(debug_info_type_line_numbers, true);
tracked!(default_visibility, Some(rustc_target::spec::SymbolVisibility::Hidden));
tracked!(dep_info_omit_d_target, true);
tracked!(direct_access_external_data, Some(true));

View File

@ -1702,6 +1702,8 @@ options! {
"threshold to allow cross crate inlining of functions"),
debug_info_for_profiling: bool = (false, parse_bool, [TRACKED],
"emit discriminators and other data necessary for AutoFDO"),
debug_info_type_line_numbers: bool = (false, parse_bool, [TRACKED],
"emit type and line information for additional data types (default: no)"),
debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
"compress debug info sections (none, zlib, zstd, default: none)"),
deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],

View File

@ -0,0 +1,7 @@
# `debug-info-type-line-numbers`
---
This option causes additional type and line information to be emitted in debug
info to provide richer information to debuggers. This is currently off by
default as it causes some compilation scenarios to be noticeably slower.

View File

@ -0,0 +1,25 @@
// This test verifies the accuracy of emitted file and line debuginfo metadata for async blocks and
// async functions.
//
//@ edition:2021
//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
// ignore-tidy-linelength
// NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-async.rs{{".*}})
// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-async.rs{{".*}})
// NONMSVC-DAG: !DISubprogram(name: "foo",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// MSVC-DAG: !DISubprogram(name: "foo",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
pub async fn foo() -> u8 {
5
}
pub fn bar() -> impl std::future::Future<Output = u8> {
// NONMSVC: !DICompositeType({{.*"}}{async_block_env#0}{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// MSVC-DAG: !DICompositeType({{.*"}}enum2$<issue_98678_async::bar::async_block_env$0>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
async {
let x: u8 = foo().await;
x + 5
}
}

View File

@ -0,0 +1,22 @@
// This test verifies the accuracy of emitted file and line debuginfo metadata for closures and
// coroutines.
//
//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
#![feature(coroutines, stmt_expr_attributes)]
// ignore-tidy-linelength
// NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-closure-coroutine.rs{{".*}})
// MSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-closure-coroutine.rs{{".*}})
pub fn foo() {
// NONMSVC-DAG: !DICompositeType({{.*"}}{closure_env#0}{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// MSVC-DAG: !DICompositeType({{.*"}}closure_env$0{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
let closure = |x| x;
closure(0);
// NONMSVC-DAG: !DICompositeType({{.*"[{]}}coroutine_env#1{{[}]".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 3]],
// MSVC-DAG: !DICompositeType({{.*".*foo::}}coroutine_env$1>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
let _coroutine = #[coroutine]
|| yield 1;
}

View File

@ -0,0 +1,40 @@
// This test verifies the accuracy of emitted file and line debuginfo metadata enums.
//
//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
// ignore-tidy-linelength
// NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-enum.rs{{".*}})
// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-enum.rs{{".*}})
// NONMSVC: !DICompositeType({{.*"}}SingleCase{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// MSVC: !DICompositeType({{.*"}}enum2$<issue_98678_enum::SingleCase>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
pub enum SingleCase {
// NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "One",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "One",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
One,
}
// NONMSVC: !DICompositeType({{.*"}}MultipleDataCases{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// MSVC: !DICompositeType({{.*"}}enum2$<issue_98678_enum::MultipleDataCases>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
pub enum MultipleDataCases {
// NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Case1",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Case1",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
Case1(u32),
// NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Case2",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Case2",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
Case2(i64),
}
// NONMSVC: !DICompositeType({{.*"}}NicheLayout{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// MSVC: !DICompositeType({{.*"}}enum2$<issue_98678_enum::NicheLayout>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
pub enum NicheLayout {
// NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Something",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Something",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
Something(&'static u32),
// NONMSVC: !DIDerivedType(tag: DW_TAG_member, name: "Nothing",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Nothing",{{.*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
Nothing,
}
pub fn foo(_: SingleCase, _: MultipleDataCases, _: NicheLayout) {}

View File

@ -0,0 +1,25 @@
// This test verifies the accuracy of emitted file and line debuginfo metadata for structs and
// unions.
//
//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
// ignore-tidy-linelength
// NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-struct-union.rs{{".*}})
// MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-struct-union.rs{{".*}})
// CHECK: !DICompositeType({{.*"}}MyType{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
pub struct MyType {
// CHECK: !DIDerivedType({{.*"}}i{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
i: i32,
}
// CHECK: !DICompositeType({{.*"}}MyUnion{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
pub union MyUnion {
// CHECK: !DIDerivedType({{.*"}}i{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
i: i32,
// CHECK: !DIDerivedType({{.*"}}f{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 1]],
f: f32,
}
pub fn foo(_: MyType, _: MyUnion) {}