summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoonas Niilola <juippis@gentoo.org>2024-12-10 09:20:00 +0200
committerJoonas Niilola <juippis@gentoo.org>2024-12-10 09:20:00 +0200
commit418188d532488b5ecfeaf19e938bed3f1aaa6d15 (patch)
tree340f00e6cf87fbd4b7d86a18f76d4f4ade7343b3 /dev-lang
parentwww-servers/tomcat: add 11.0.2 (diff)
downloadgentoo-418188d532488b5ecfeaf19e938bed3f1aaa6d15.tar.gz
gentoo-418188d532488b5ecfeaf19e938bed3f1aaa6d15.tar.bz2
gentoo-418188d532488b5ecfeaf19e938bed3f1aaa6d15.zip
dev-lang/rust: fix LLVM assertion with debug info in 1.83.0
- the patch is rebased for 1.83, but merged upstream to 1.84. Closes: https://bugs.gentoo.org/946158 Signed-off-by: Joonas Niilola <juippis@gentoo.org>
Diffstat (limited to 'dev-lang')
-rw-r--r--dev-lang/rust/files/1.83.0-dwarf-llvm-assertion.patch242
-rw-r--r--dev-lang/rust/rust-1.83.0-r1.ebuild (renamed from dev-lang/rust/rust-1.83.0.ebuild)1
2 files changed, 243 insertions, 0 deletions
diff --git a/dev-lang/rust/files/1.83.0-dwarf-llvm-assertion.patch b/dev-lang/rust/files/1.83.0-dwarf-llvm-assertion.patch
new file mode 100644
index 000000000000..64d00ac0aaaf
--- /dev/null
+++ b/dev-lang/rust/files/1.83.0-dwarf-llvm-assertion.patch
@@ -0,0 +1,242 @@
+From 1dc106121b62562ead6e7d612fa136dc4b35cd5d Mon Sep 17 00:00:00 2001
+From: Kyle Huey <khuey@kylehuey.com>
+Date: Mon, 4 Nov 2024 11:38:14 -0800
+Subject: [PATCH] Add discriminators to DILocations when multiple functions are
+ inlined into a single point.
+
+LLVM does not expect to ever see multiple dbg_declares for the same variable at the same
+location with different values. proc-macros make it possible for arbitrary code,
+including multiple calls that get inlined, to happen at any given location in the source
+code. Add discriminators when that happens so these locations are different to LLVM.
+
+This may interfere with the AddDiscriminators pass in LLVM, which is added by the
+unstable flag -Zdebug-info-for-profiling.
+
+Fixes #131944
+---
+ .../src/debuginfo/create_scope_map.rs | 60 ++++++++++++++++++-
+ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 ++
+ .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 8 +++
+ .../auxiliary/macro_def.rs | 11 ++++
+ .../mir_inlined_twice_var_locs.rs | 53 ++++++++++++++++
+ 5 files changed, 133 insertions(+), 3 deletions(-)
+ create mode 100644 tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs
+ create mode 100644 tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs
+
+diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+index ac6c2fb1b83a6..0f1909486ec7e 100644
+--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
++++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+@@ -1,11 +1,15 @@
++use std::collections::hash_map::Entry;
++
+ use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
+ use rustc_codegen_ssa::traits::*;
++use rustc_data_structures::fx::FxHashMap;
+ use rustc_index::Idx;
+ use rustc_index::bit_set::BitSet;
+ use rustc_middle::mir::{Body, SourceScope};
+ use rustc_middle::ty::layout::FnAbiOf;
+ use rustc_middle::ty::{self, Instance};
+ use rustc_session::config::DebugInfo;
++use rustc_span::BytePos;
+
+ use super::metadata::file_metadata;
+ use super::utils::DIB;
+@@ -37,10 +41,20 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
+ None
+ };
+ let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
++ let mut discriminators = FxHashMap::default();
+ // Instantiate all scopes.
+ for idx in 0..mir.source_scopes.len() {
+ let scope = SourceScope::new(idx);
+- make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope);
++ make_mir_scope(
++ cx,
++ instance,
++ mir,
++ &variables,
++ debug_context,
++ &mut instantiated,
++ &mut discriminators,
++ scope,
++ );
+ }
+ assert!(instantiated.count() == mir.source_scopes.len());
+ }
+@@ -52,6 +66,7 @@ fn make_mir_scope<'ll, 'tcx>(
+ variables: &Option<BitSet<SourceScope>>,
+ debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
+ instantiated: &mut BitSet<SourceScope>,
++ discriminators: &mut FxHashMap<BytePos, u32>,
+ scope: SourceScope,
+ ) {
+ if instantiated.contains(scope) {
+@@ -60,7 +75,16 @@ fn make_mir_scope<'ll, 'tcx>(
+
+ let scope_data = &mir.source_scopes[scope];
+ let parent_scope = if let Some(parent) = scope_data.parent_scope {
+- make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent);
++ make_mir_scope(
++ cx,
++ instance,
++ mir,
++ variables,
++ debug_context,
++ instantiated,
++ discriminators,
++ parent,
++ );
+ debug_context.scopes[parent]
+ } else {
+ // The root is the function itself.
+@@ -117,7 +141,37 @@ fn make_mir_scope<'ll, 'tcx>(
+ // FIXME(eddyb) this doesn't account for the macro-related
+ // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
+ let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
+- cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span)
++ let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
++
++ // NB: In order to produce proper debug info for variables (particularly
++ // arguments) in multiply-inline functions, LLVM expects to see a single
++ // DILocalVariable with multiple different DILocations in the IR. While
++ // the source information for each DILocation would be identical, their
++ // inlinedAt attributes will be unique to the particular callsite.
++ //
++ // We generate DILocations here based on the callsite's location in the
++ // source code. A single location in the source code usually can't
++ // produce multiple distinct calls so this mostly works, until
++ // proc-macros get involved. A proc-macro can generate multiple calls
++ // at the same span, which breaks the assumption that we're going to
++ // produce a unique DILocation for every scope we process here. We
++ // have to explicitly add discriminators if we see inlines into the
++ // same source code location.
++ //
++ // Note further that we can't key this hashtable on the span itself,
++ // because these spans could have distinct SyntaxContexts. We have
++ // to key on exactly what we're giving to LLVM.
++ match discriminators.entry(callsite_span.lo()) {
++ Entry::Occupied(mut o) => {
++ *o.get_mut() += 1;
++ unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
++ .expect("Failed to encode discriminator in DILocation")
++ }
++ Entry::Vacant(v) => {
++ v.insert(0);
++ loc
++ }
++ }
+ });
+
+ debug_context.scopes[scope] = DebugScope {
+diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+index 3d2e270a3868e..75a5ec44c2285 100644
+--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
++++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+@@ -2174,6 +2174,10 @@ unsafe extern "C" {
+ Scope: &'a DIScope,
+ InlinedAt: Option<&'a DILocation>,
+ ) -> &'a DILocation;
++ pub fn LLVMRustDILocationCloneWithBaseDiscriminator<'a>(
++ Location: &'a DILocation,
++ BD: c_uint,
++ ) -> Option<&'a DILocation>;
+ pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
+ pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
+ pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
+diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+index 9330c83b7f230..cd70c3f266920 100644
+--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
++++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+@@ -1305,6 +1305,14 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
+ return wrap(Loc);
+ }
+
++extern "C" LLVMMetadataRef
++LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location,
++ unsigned BD) {
++ DILocation *Loc = unwrapDIPtr<DILocation>(Location);
++ auto NewLoc = Loc->cloneWithBaseDiscriminator(BD);
++ return wrap(NewLoc.has_value() ? NewLoc.value() : nullptr);
++}
++
+ extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
+ return dwarf::DW_OP_deref;
+ }
+diff --git a/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs b/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs
+new file mode 100644
+index 0000000000000..159ecfd09743d
+--- /dev/null
++++ b/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs
+@@ -0,0 +1,11 @@
++//@ force-host
++//@ no-prefer-dynamic
++#![crate_type = "proc-macro"]
++
++extern crate proc_macro;
++use proc_macro::*;
++
++#[proc_macro]
++pub fn square_twice(_item: TokenStream) -> TokenStream {
++ "(square(env::vars().count() as i32), square(env::vars().count() as i32))".parse().unwrap()
++}
+diff --git a/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs b/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs
+new file mode 100644
+index 0000000000000..c3858044c0c9f
+--- /dev/null
++++ b/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs
+@@ -0,0 +1,53 @@
++//@ min-llvm-version: 19
++//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline
++// MSVC is different because of the individual allocas.
++//@ ignore-msvc
++
++//@ aux-build:macro_def.rs
++
++// Find the variable.
++// CHECK-DAG: ![[#var_dbg:]] = !DILocalVariable(name: "n",{{( arg: 1,)?}} scope: ![[#var_scope:]]
++
++// Find both dbg_declares. These will proceed the variable metadata, of course, so we're looking
++// backwards.
++// CHECK-DAG: dbg_declare(ptr %n.dbg.spill{{[0-9]}}, ![[#var_dbg]], !DIExpression(), ![[#var_loc2:]])
++// CHECK-DAG: dbg_declare(ptr %n.dbg.spill, ![[#var_dbg]], !DIExpression(), ![[#var_loc1:]])
++
++// Find the first location definition, looking forwards again.
++// CHECK: ![[#var_loc1]] = !DILocation
++// CHECK-SAME: scope: ![[#var_scope:]], inlinedAt: ![[#var_inlinedAt1:]]
++
++// Find the first location's inlinedAt
++// NB: If we fail here it's *probably* because we failed to produce two
++// different locations and ended up reusing an earlier one.
++// CHECK: ![[#var_inlinedAt1]] = !DILocation
++// CHECK-SAME: scope: ![[var_inlinedAt1_scope:]]
++
++// Find the second location definition, still looking forwards.
++// NB: If we failed to produce two different locations, the test will
++// definitely fail by this point (if it hasn't already) because we won't
++// be able to find the same line again.
++// CHECK: ![[#var_loc2]] = !DILocation
++// CHECK-SAME: scope: ![[#var_scope]], inlinedAt: ![[#var_inlinedAt2:]]
++
++// Find the second location's inlinedAt.
++// CHECK: ![[#var_inlinedAt2]] = !DILocation
++// CHECK-SAME: scope: ![[#var_inlinedAt2_scope:]]
++
++// Finally, check that a discriminator was emitted for the second scope.
++// FIXMEkhuey ideally we would check that *either* scope has a discriminator
++// but I don't know that it's possible to check that with FileCheck.
++// CHECK: ![[#var_inlinedAt2_scope]] = !DILexicalBlockFile
++// CHECK-SAME: discriminator: [[#]]
++extern crate macro_def;
++
++use std::env;
++
++fn square(n: i32) -> i32 {
++ n * n
++}
++
++fn main() {
++ let (z1, z2) = macro_def::square_twice!();
++ println!("{z1} == {z2}");
++}
diff --git a/dev-lang/rust/rust-1.83.0.ebuild b/dev-lang/rust/rust-1.83.0-r1.ebuild
index b0585b3218c1..db171b2fb483 100644
--- a/dev-lang/rust/rust-1.83.0.ebuild
+++ b/dev-lang/rust/rust-1.83.0-r1.ebuild
@@ -135,6 +135,7 @@ PATCHES=(
"${FILESDIR}"/1.83.0-cross-compile-libz.patch
#"${FILESDIR}"/1.72.0-bump-libc-deps-to-0.2.146.patch # pending refresh
"${FILESDIR}"/1.67.0-doc-wasm.patch
+ "${FILESDIR}"/1.83.0-dwarf-llvm-assertion.patch
)
clear_vendor_checksums() {