diff options
author | Joonas Niilola <juippis@gentoo.org> | 2024-12-10 09:20:00 +0200 |
---|---|---|
committer | Joonas Niilola <juippis@gentoo.org> | 2024-12-10 09:20:00 +0200 |
commit | 418188d532488b5ecfeaf19e938bed3f1aaa6d15 (patch) | |
tree | 340f00e6cf87fbd4b7d86a18f76d4f4ade7343b3 /dev-lang | |
parent | www-servers/tomcat: add 11.0.2 (diff) | |
download | gentoo-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.patch | 242 | ||||
-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() { |