--- /dev/null
+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());
++ }
++}