-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
upstream fix for "Cannot represent a difference across sections"; rel 3
from: rust-lang/rust#111167
- Loading branch information
Showing
2 changed files
with
251 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
From 10b69dde3fd15334ea2382d2dc9e9a261de1afaf Mon Sep 17 00:00:00 2001 | ||
From: Josh Stone <jistone@redhat.com> | ||
Date: Wed, 3 May 2023 15:52:31 -0700 | ||
Subject: [PATCH] debuginfo: split method declaration and definition | ||
|
||
When we're adding a method to a type DIE, we only want a DW_AT_declaration | ||
there, because LLVM LTO can't unify type definitions when a child DIE is a | ||
full subprogram definition. Now the subprogram definition gets added at the | ||
CU level with a specification link back to the abstract declaration. | ||
--- | ||
.../rustc_codegen_llvm/src/debuginfo/mod.rs | 85 +++++++++++-------- | ||
compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 15 ++++ | ||
.../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 22 +++++ | ||
.../issue-109934-lto-debuginfo/Makefile | 12 +++ | ||
.../issue-109934-lto-debuginfo/lib.rs | 9 ++ | ||
5 files changed, 109 insertions(+), 34 deletions(-) | ||
create mode 100644 tests/run-make/issue-109934-lto-debuginfo/Makefile | ||
create mode 100644 tests/run-make/issue-109934-lto-debuginfo/lib.rs | ||
|
||
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | ||
index 2e9f89f419696..b138b0c0e70a1 100644 | ||
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | ||
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | ||
@@ -322,7 +322,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { | ||
let tcx = self.tcx; | ||
|
||
let def_id = instance.def_id(); | ||
- let containing_scope = get_containing_scope(self, instance); | ||
+ let (containing_scope, is_method) = get_containing_scope(self, instance); | ||
let span = tcx.def_span(def_id); | ||
let loc = self.lookup_debug_loc(span.lo()); | ||
let file_metadata = file_metadata(self, &loc.file); | ||
@@ -378,8 +378,29 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { | ||
} | ||
} | ||
|
||
- unsafe { | ||
- return llvm::LLVMRustDIBuilderCreateFunction( | ||
+ // When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because | ||
+ // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition. | ||
+ // When we use this `decl` below, the subprogram definition gets created at the CU level | ||
+ // with a DW_AT_specification pointing back to the type's declaration. | ||
+ let decl = is_method.then(|| unsafe { | ||
+ llvm::LLVMRustDIBuilderCreateMethod( | ||
+ DIB(self), | ||
+ containing_scope, | ||
+ name.as_ptr().cast(), | ||
+ name.len(), | ||
+ linkage_name.as_ptr().cast(), | ||
+ linkage_name.len(), | ||
+ file_metadata, | ||
+ loc.line, | ||
+ function_type_metadata, | ||
+ flags, | ||
+ spflags & !DISPFlags::SPFlagDefinition, | ||
+ template_parameters, | ||
+ ) | ||
+ }); | ||
+ | ||
+ return unsafe { | ||
+ llvm::LLVMRustDIBuilderCreateFunction( | ||
DIB(self), | ||
containing_scope, | ||
name.as_ptr().cast(), | ||
@@ -394,9 +415,9 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { | ||
spflags, | ||
maybe_definition_llfn, | ||
template_parameters, | ||
- None, | ||
- ); | ||
- } | ||
+ decl, | ||
+ ) | ||
+ }; | ||
|
||
fn get_function_signature<'ll, 'tcx>( | ||
cx: &CodegenCx<'ll, 'tcx>, | ||
@@ -493,14 +514,16 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { | ||
names | ||
} | ||
|
||
+ /// Returns a scope, plus `true` if that's a type scope for "class" methods, | ||
+ /// otherwise `false` for plain namespace scopes. | ||
fn get_containing_scope<'ll, 'tcx>( | ||
cx: &CodegenCx<'ll, 'tcx>, | ||
instance: Instance<'tcx>, | ||
- ) -> &'ll DIScope { | ||
+ ) -> (&'ll DIScope, bool) { | ||
// First, let's see if this is a method within an inherent impl. Because | ||
// if yes, we want to make the result subroutine DIE a child of the | ||
// subroutine's self-type. | ||
- let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| { | ||
+ if let Some(impl_def_id) = cx.tcx.impl_of_method(instance.def_id()) { | ||
// If the method does *not* belong to a trait, proceed | ||
if cx.tcx.trait_id_of_impl(impl_def_id).is_none() { | ||
let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions( | ||
@@ -511,39 +534,33 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { | ||
|
||
// Only "class" methods are generally understood by LLVM, | ||
// so avoid methods on other types (e.g., `<*mut T>::null`). | ||
- match impl_self_ty.kind() { | ||
- ty::Adt(def, ..) if !def.is_box() => { | ||
- // Again, only create type information if full debuginfo is enabled | ||
- if cx.sess().opts.debuginfo == DebugInfo::Full | ||
- && !impl_self_ty.needs_subst() | ||
- { | ||
- Some(type_di_node(cx, impl_self_ty)) | ||
- } else { | ||
- Some(namespace::item_namespace(cx, def.did())) | ||
- } | ||
+ if let ty::Adt(def, ..) = impl_self_ty.kind() && !def.is_box() { | ||
+ // Again, only create type information if full debuginfo is enabled | ||
+ if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.needs_subst() | ||
+ { | ||
+ return (type_di_node(cx, impl_self_ty), true); | ||
+ } else { | ||
+ return (namespace::item_namespace(cx, def.did()), false); | ||
} | ||
- _ => None, | ||
} | ||
} else { | ||
// For trait method impls we still use the "parallel namespace" | ||
// strategy | ||
- None | ||
} | ||
- }); | ||
+ } | ||
|
||
- self_type.unwrap_or_else(|| { | ||
- namespace::item_namespace( | ||
- cx, | ||
- DefId { | ||
- krate: instance.def_id().krate, | ||
- index: cx | ||
- .tcx | ||
- .def_key(instance.def_id()) | ||
- .parent | ||
- .expect("get_containing_scope: missing parent?"), | ||
- }, | ||
- ) | ||
- }) | ||
+ let scope = namespace::item_namespace( | ||
+ cx, | ||
+ DefId { | ||
+ krate: instance.def_id().krate, | ||
+ index: cx | ||
+ .tcx | ||
+ .def_key(instance.def_id()) | ||
+ .parent | ||
+ .expect("get_containing_scope: missing parent?"), | ||
+ }, | ||
+ ); | ||
+ (scope, false) | ||
} | ||
} | ||
|
||
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs | ||
index c95148013eb74..1f98d91c32054 100644 | ||
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs | ||
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs | ||
@@ -1987,6 +1987,21 @@ extern "C" { | ||
Decl: Option<&'a DIDescriptor>, | ||
) -> &'a DISubprogram; | ||
|
||
+ pub fn LLVMRustDIBuilderCreateMethod<'a>( | ||
+ Builder: &DIBuilder<'a>, | ||
+ Scope: &'a DIDescriptor, | ||
+ Name: *const c_char, | ||
+ NameLen: size_t, | ||
+ LinkageName: *const c_char, | ||
+ LinkageNameLen: size_t, | ||
+ File: &'a DIFile, | ||
+ LineNo: c_uint, | ||
+ Ty: &'a DIType, | ||
+ Flags: DIFlags, | ||
+ SPFlags: DISPFlags, | ||
+ TParam: &'a DIArray, | ||
+ ) -> &'a DISubprogram; | ||
+ | ||
pub fn LLVMRustDIBuilderCreateBasicType<'a>( | ||
Builder: &DIBuilder<'a>, | ||
Name: *const c_char, | ||
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | ||
index cadb6b1e23fe9..49acd71b3e106 100644 | ||
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | ||
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | ||
@@ -831,6 +831,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( | ||
return wrap(Sub); | ||
} | ||
|
||
+extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod( | ||
+ LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, | ||
+ const char *Name, size_t NameLen, | ||
+ const char *LinkageName, size_t LinkageNameLen, | ||
+ LLVMMetadataRef File, unsigned LineNo, | ||
+ LLVMMetadataRef Ty, LLVMRustDIFlags Flags, | ||
+ LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) { | ||
+ DITemplateParameterArray TParams = | ||
+ DITemplateParameterArray(unwrap<MDTuple>(TParam)); | ||
+ DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags); | ||
+ DINode::DIFlags llvmFlags = fromRust(Flags); | ||
+ DISubprogram *Sub = Builder->createMethod( | ||
+ unwrapDI<DIScope>(Scope), | ||
+ StringRef(Name, NameLen), | ||
+ StringRef(LinkageName, LinkageNameLen), | ||
+ unwrapDI<DIFile>(File), LineNo, | ||
+ unwrapDI<DISubroutineType>(Ty), | ||
+ 0, 0, nullptr, // VTable params aren't used | ||
+ llvmFlags, llvmSPFlags, TParams); | ||
+ return wrap(Sub); | ||
+} | ||
+ | ||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType( | ||
LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, | ||
uint64_t SizeInBits, unsigned Encoding) { | ||
diff --git a/tests/run-make/issue-109934-lto-debuginfo/Makefile b/tests/run-make/issue-109934-lto-debuginfo/Makefile | ||
new file mode 100644 | ||
index 0000000000000..3b7a99d3dbc62 | ||
--- /dev/null | ||
+++ b/tests/run-make/issue-109934-lto-debuginfo/Makefile | ||
@@ -0,0 +1,12 @@ | ||
+# ignore-cross-compile | ||
+include ../tools.mk | ||
+ | ||
+# With the upgrade to LLVM 16, this was getting: | ||
+# | ||
+# error: Cannot represent a difference across sections | ||
+# | ||
+# The error stemmed from DI function definitions under type scopes, fixed by | ||
+# only declaring in type scope and defining the subprogram elsewhere. | ||
+ | ||
+all: | ||
+ $(RUSTC) lib.rs --test -C lto=fat -C debuginfo=2 -C incremental=$(TMPDIR)/inc-fat | ||
diff --git a/tests/run-make/issue-109934-lto-debuginfo/lib.rs b/tests/run-make/issue-109934-lto-debuginfo/lib.rs | ||
new file mode 100644 | ||
index 0000000000000..c405928bd1824 | ||
--- /dev/null | ||
+++ b/tests/run-make/issue-109934-lto-debuginfo/lib.rs | ||
@@ -0,0 +1,9 @@ | ||
+extern crate alloc; | ||
+ | ||
+#[cfg(test)] | ||
+mod tests { | ||
+ #[test] | ||
+ fn something_alloc() { | ||
+ assert_eq!(Vec::<u32>::new(), Vec::<u32>::new()); | ||
+ } | ||
+} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters