Auto merge of #89917 - davidtwco:issue-60705-stabilize-rust-symbol-mangling-scheme, r=wesleywiser

sess: default to v0 symbol mangling on nightly

cc rust-lang/rust#60705 rust-lang/compiler-team#938

Rust's current mangling scheme depends on compiler internals; loses information about generic parameters (and other things) which makes for a worse experience when using external tools that need to interact with Rust symbol names; is inconsistent; and can contain `.` characters which aren't universally supported. Therefore, Rust has defined its own symbol mangling scheme which is defined in terms of the Rust language, not the compiler implementation; encodes information about generic parameters in a reversible way; has a consistent definition; and generates symbols that only use the characters `A-Z`, `a-z`, `0-9`, and `_`.

Support for the new Rust symbol mangling scheme has been added to upstream tools that will need to interact with Rust symbols (e.g. debuggers).

This pull request changes the default symbol mangling scheme from the legacy scheme to the new Rust mangling scheme on nightly.

The following pull requests implemented v0 mangling in rustc (if I'm missing any, let me know):

- rust-lang/rust#57967
- rust-lang/rust#63559
- rust-lang/rust#75675
- rust-lang/rust#77452
- rust-lang/rust#77554
- rust-lang/rust#83767
- rust-lang/rust#87194
- rust-lang/rust#87789

Rust's symbol mangling scheme has support in the following external tools:

- `binutils`/`gdb` (GNU `libiberty`)
    - [[PATCH] Move rust_{is_mangled,demangle_sym} to a private libiberty header.
](https://gcc.gnu.org/pipermail/gcc-patches/2019-June/523011.html) committed as 979526c9ce
    - [[PATCH] Simplify and generalize rust-demangle's unescaping logic.
](https://gcc.gnu.org/pipermail/gcc-patches/2019-August/527835.html) committed as 42bf58bb13
    - [[PATCH] Remove some restrictions from rust-demangle.
](https://gcc.gnu.org/pipermail/gcc-patches/2019-September/530445.html) committed as e1cb00db67
    - [[PATCH] Refactor rust-demangle to be independent of C++ demangling.
](https://gcc.gnu.org/pipermail/gcc-patches/2019-November/533719.html) ([original submission](https://gcc.gnu.org/pipermail/gcc-patches/2019-October/532388.html)) committed as 32fc3719e0
    - [[PATCH] Support the new ("v0") mangling scheme in rust-demangle.
](https://gcc.gnu.org/pipermail/gcc-patches/2020-November/558905.html) ([original submission](https://gcc.gnu.org/pipermail/gcc-patches/2020-March/542012.html)) committed as 84096498a7
- `lldb`/`llvm-objdump`/`llvm-nm`/`llvm-symbolizer`/`llvm-cxxfilt`/etc
  - 7310403e3c
  - c8c2b4629f
  - 0a2d4f3f24
- Linux `perf`
- `valgrind`
  - [Update demangler to support Rust v0 name mangling.](https://bugs.kde.org/show_bug.cgi?id=431306)

https://github.com/rust-lang/rust/pull/85530#issuecomment-857855379 contains a summary of the most recent crater run of the v0 mangling, and the remaining issues from that were fixed by rust-lang/rust#87194 (confirmed by follow-up crater run, https://github.com/rust-lang/rust/pull/85530#issuecomment-883679416).

`@rustbot` label +T-compiler
r? `@michaelwoerister`
This commit is contained in:
bors 2025-11-20 04:26:30 +00:00
commit 683dd08db5
20 changed files with 61 additions and 55 deletions

View file

@ -1530,7 +1530,11 @@ impl Options {
}
pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
self.cg.symbol_mangling_version.unwrap_or(if self.unstable_features.is_nightly_build() {
SymbolManglingVersion::V0
} else {
SymbolManglingVersion::Legacy
})
}
#[inline]

View file

@ -47,6 +47,6 @@ foo::example_function
## Mangling versions
`rustc` supports different mangling versions which encode the names in different ways.
The legacy version (which is currently the default) is not described here.
The legacy version (which is currently the default on beta/stable) is not described here.
The "v0" mangling scheme addresses several limitations of the legacy format,
and is described in the [v0 Symbol Format](v0.md) chapter.

View file

@ -13,7 +13,7 @@ use std::arch::x86_64::{__m128, _mm_blend_ps};
pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128, ret: *mut __m128) {
let f = {
// check that _mm_blend_ps is not being inlined into the closure
// CHECK-LABEL: {{sse41_blend_nofeature.*closure.*:}}
// CHECK-LABEL: {{sse41_blend_nofeature:}}
// CHECK-NOT: blendps
// CHECK: {{call .*_mm_blend_ps.*}}
// CHECK-NOT: blendps
@ -29,7 +29,7 @@ pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128, ret: *mut __m128) {
pub fn sse41_blend_noinline(x: __m128, y: __m128) -> __m128 {
let f = {
// check that _mm_blend_ps is being inlined into the closure
// CHECK-LABEL: {{sse41_blend_noinline.*closure.*:}}
// CHECK-LABEL: {{sse41_blend_noinline:}}
// CHECK-NOT: _mm_blend_ps
// CHECK: blendps
// CHECK-NOT: _mm_blend_ps
@ -45,10 +45,10 @@ pub fn sse41_blend_noinline(x: __m128, y: __m128) -> __m128 {
pub fn sse41_blend_doinline(x: __m128, y: __m128) -> __m128 {
// check that the closure and _mm_blend_ps are being inlined into the function
// CHECK-LABEL: sse41_blend_doinline:
// CHECK-NOT: {{sse41_blend_doinline.*closure.*}}
// CHECK-NOT: {{sse41_blend_doinline:}}
// CHECK-NOT: _mm_blend_ps
// CHECK: blendps
// CHECK-NOT: {{sse41_blend_doinline.*closure.*}}
// CHECK-NOT: {{sse41_blend_doinline.*}}
// CHECK-NOT: _mm_blend_ps
// CHECK: ret
let f = {

View file

@ -12,7 +12,7 @@
extern crate breakpoint_panic_handler;
// Verify function name doesn't contain unacceaptable characters.
// CHECK: .func (.param .b32 func_retval0) [[IMPL_FN:[a-zA-Z0-9$_]+square[a-zA-Z0-9$_]+]]
// CHECK: .func (.param .b32 func_retval0) [[IMPL_FN:[a-zA-Z0-9$_]+square]]
// CHECK-LABEL: .visible .entry top_kernel(
#[no_mangle]

View file

@ -7,7 +7,7 @@
#[no_mangle]
pub fn iota() -> [u8; 16] {
// OPT-NOT: core..array..Guard
// NORMAL: core..array..Guard
// OPT-NOT: core::array::Guard
// NORMAL: core::array::Guard
std::array::from_fn(|i| i as _)
}

View file

@ -1,4 +1,4 @@
//@ compile-flags: -Copt-level=3
//@ compile-flags: -Copt-level=3 --crate-name=test
//@ ignore-std-debug-assertions
#![crate_type = "lib"]

View file

@ -20,7 +20,7 @@ pub async fn async_block() {
f.await;
}
x(
// CHECK-LABEL: ; cold_attribute::async_block::{{{{closure}}}}::{{{{closure}}}}
// CHECK-LABEL: ; cold_attribute::async_block::{closure#0}::{closure#0}
// CHECK-NEXT: Function Attrs: cold {{.*}}
#[cold]
async {},
@ -33,7 +33,7 @@ pub fn closure() {
f()
}
x(
// CHECK-LABEL: ; cold_attribute::closure::{{{{closure}}}}
// CHECK-LABEL: ; cold_attribute::closure::{closure#0}
// CHECK-NEXT: Function Attrs: cold {{.*}}
#[cold]
|| {},
@ -43,14 +43,14 @@ pub fn closure() {
pub struct S;
impl S {
// CHECK-LABEL: ; cold_attribute::S::method
// CHECK-LABEL: ; <cold_attribute::S>::method
// CHECK-NEXT: Function Attrs: cold {{.*}}
#[cold]
pub fn method(&self) {}
}
pub trait Trait {
// CHECK-LABEL: ; cold_attribute::Trait::trait_fn
// CHECK-LABEL: ; <cold_attribute::S as cold_attribute::Trait>::trait_fn
// CHECK-NEXT: Function Attrs: cold {{.*}}
#[cold]
fn trait_fn(&self) {}

View file

@ -2,7 +2,7 @@
// The iterator may unroll for values smaller than a certain threshold so we
// use a larger value to prevent unrolling.
//@ compile-flags: -Copt-level=3
//@ compile-flags: -Copt-level=3 --crate-name=test
#![crate_type = "lib"]

View file

@ -20,11 +20,11 @@ fn test(x: u64) {
}
// CHECK: .balign 4
// CHECK: add rax, 2
// CHECK: add rax, 1
// CHECK: add rax, 42
// CHECK: .balign 4
// CHECK: add rax, 1
// CHECK: add rax, 2
// CHECK: add rax, 42
#[unsafe(naked)]

View file

@ -7,10 +7,10 @@
#[inline(never)]
fn test<const SIZE: usize>() {
// CHECK-LABEL: no_alloca_inside_if_false::test
// CHECK-LABEL: no_alloca_inside_if_false::test::<8192>
// CHECK: start:
// CHECK-NEXT: alloca [{{12|24}} x i8]
// CHECK-NOT: alloca
// CHECK-NEXT: = alloca [{{12|24}} x i8]
// CHECK-NOT: = alloca
if const { SIZE < 4096 } {
let arr = [0u8; SIZE];
std::hint::black_box(&arr);

View file

@ -13,13 +13,13 @@
use std::ptr::NonNull;
// CHECK-LABEL: ; core::ptr::non_null::NonNull<T>::new_unchecked
// CHECK-LABEL: ; <core::ptr::non_null::NonNull<u8>>::new_unchecked
// CHECK-NOT: call
// CHECK: }
// CHECK-LABEL: @nonnull_new
#[no_mangle]
pub unsafe fn nonnull_new(ptr: *mut u8) -> NonNull<u8> {
// CHECK: ; call core::ptr::non_null::NonNull<T>::new_unchecked
// CHECK: ; call <core::ptr::non_null::NonNull<u8>>::new_unchecked
unsafe { NonNull::new_unchecked(ptr) }
}

View file

@ -9,7 +9,7 @@
#![crate_type = "lib"]
// CHECK-LABEL: define{{.*}}4core3ptr47drop_in_place$LT$dyn$u20$core..marker..Send$GT$
// CHECK-LABEL: define{{.*}}4core3ptr13drop_in_placeDNtNtB4_6marker4Send
// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
// CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE")
@ -20,7 +20,7 @@ struct PresentDrop;
impl Drop for PresentDrop {
fn drop(&mut self) {}
// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}PresentDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place{{.*}}PresentDrop{{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
}
pub fn foo() {

View file

@ -54,11 +54,11 @@ pub fn main() {
// `DynCompatible` is indeed dyn-compatible.
let _: &dyn DynCompatible = &s;
// CHECK: call <fn_ptr_reify_shim::S as fn_ptr_reify_shim::DynCompatible>::dyn_name{{.*}}reify.shim.fnptr
// CHECK: call <fn_ptr_reify_shim::S as fn_ptr_reify_shim::DynCompatible>::dyn_name::{shim:reify_fnptr#0}
let dyn_name = S::dyn_name as fn(&S) -> &str;
let _unused = dyn_name(&s);
// CHECK: call fn_ptr_reify_shim::DynCompatible::dyn_name_default{{.*}}reify.shim.fnptr
// CHECK: call <fn_ptr_reify_shim::S as fn_ptr_reify_shim::DynCompatible>::dyn_name_default::{shim:reify_fnptr#0}
let dyn_name_default = S::dyn_name_default as fn(&S) -> &str;
let _unused = dyn_name_default(&s);
@ -68,7 +68,7 @@ pub fn main() {
let not_dyn_name = S::not_dyn_name as fn() -> &'static str;
let _unused = not_dyn_name();
// CHECK: call fn_ptr_reify_shim::NotDynCompatible::not_dyn_name_default{{$}}
// CHECK: call <fn_ptr_reify_shim::S as fn_ptr_reify_shim::NotDynCompatible>::not_dyn_name_default{{$}}
let not_dyn_name_default = S::not_dyn_name_default as fn() -> &'static str;
let _unused = not_dyn_name_default();
}

View file

@ -29,7 +29,7 @@ impl MyTrait for Thing {}
// the shim calls the real function
// CHECK-LABEL: define
// CHECK-SAME: my_naked_function
// CHECK-SAME: reify.shim.fnptr
// CHECK-SAME: reify_fnptr
// CHECK-LABEL: main
#[unsafe(no_mangle)]
@ -40,7 +40,7 @@ pub fn main() {
// main calls the shim function
// CHECK: call void
// CHECK-SAME: my_naked_function
// CHECK-SAME: reify.shim.fnptr
// CHECK-SAME: reify_fnptr
(F)(&Thing);
}

View file

@ -66,7 +66,7 @@ pub trait MyTrait {
fn unsanitized(&self, b: &mut u8) -> u8;
fn sanitized(&self, b: &mut u8) -> u8;
// CHECK-LABEL: ; sanitize_off::MyTrait::unsanitized_default
// CHECK-LABEL: ; <() as sanitize_off::MyTrait>::unsanitized_default
// CHECK-NEXT: ; Function Attrs:
// CHECK-NOT: sanitize_address
// CHECK: start:
@ -77,7 +77,7 @@ pub trait MyTrait {
*b
}
// CHECK-LABEL: ; sanitize_off::MyTrait::sanitized_default
// CHECK-LABEL: ; <() as sanitize_off::MyTrait>::sanitized_default
// CHECK-NEXT: ; Function Attrs:
// CHECK: sanitize_address
// CHECK: start:

View file

@ -9,35 +9,35 @@
// lldb-command:run
// lldb-command:v B
// lldb-check: ::B::[...] = false
// lldb-check: ::B = false
// lldb-command:v I
// lldb-check: ::I::[...] = -1
// lldb-check: ::I = -1
// lldb-command:v --format=d C
// lldb-check: ::C::[...] = 97
// lldb-check: ::C = 97
// lldb-command:v --format=d I8
// lldb-check: ::I8::[...] = 68
// lldb-check: ::I8 = 68
// lldb-command:v I16
// lldb-check: ::I16::[...] = -16
// lldb-check: ::I16 = -16
// lldb-command:v I32
// lldb-check: ::I32::[...] = -32
// lldb-check: ::I32 = -32
// lldb-command:v I64
// lldb-check: ::I64::[...] = -64
// lldb-check: ::I64 = -64
// lldb-command:v U
// lldb-check: ::U::[...] = 1
// lldb-check: ::U = 1
// lldb-command:v --format=d U8
// lldb-check: ::U8::[...] = 100
// lldb-check: ::U8 = 100
// lldb-command:v U16
// lldb-check: ::U16::[...] = 16
// lldb-check: ::U16 = 16
// lldb-command:v U32
// lldb-check: ::U32::[...] = 32
// lldb-check: ::U32 = 32
// lldb-command:v U64
// lldb-check: ::U64::[...] = 64
// lldb-check: ::U64 = 64
// lldb-command:v F16
// lldb-check: ::F16::[...] = 1.5
// lldb-check: ::F16 = 1.5
// lldb-command:v F32
// lldb-check: ::F32::[...] = 2.5
// lldb-check: ::F32 = 2.5
// lldb-command:v F64
// lldb-check: ::F64::[...] = 3.5
// lldb-check: ::F64 = 3.5
// gdb-command:run
// gdb-command:print B
@ -103,4 +103,6 @@ fn main() {
let b = unsafe { F16 };
}
fn _zzz() {()}
fn _zzz() {
()
}

View file

@ -14,7 +14,7 @@
// lldb-command:v TEST
// lldb-check:(unsigned long) TEST = 3735928559
// lldb-command:v OTHER_TEST
// lldb-check:(unsigned long) no_mangle_info::namespace::OTHER_TEST::[...] = 42
// lldb-check:(unsigned long) no_mangle_info::namespace::OTHER_TEST = 42
// === CDB TESTS ==================================================================================
// cdb-command: g

View file

@ -4,12 +4,12 @@ debug!!!
stack backtrace:
0: std::panicking::begin_panic
1: short_ice_remove_middle_frames_2::eight
2: short_ice_remove_middle_frames_2::seven::{{closure}}
2: short_ice_remove_middle_frames_2::seven::{closure#0}
[... omitted 3 frames ...]
3: short_ice_remove_middle_frames_2::fifth
4: short_ice_remove_middle_frames_2::fourth::{{closure}}
4: short_ice_remove_middle_frames_2::fourth::{closure#0}
[... omitted 4 frames ...]
5: short_ice_remove_middle_frames_2::first
6: short_ice_remove_middle_frames_2::main
7: core::ops::function::FnOnce::call_once
7: <fn() as core::ops::function::FnOnce<()>>::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

View file

@ -5,11 +5,11 @@ stack backtrace:
0: std::panicking::begin_panic
1: short_ice_remove_middle_frames::seven
2: short_ice_remove_middle_frames::sixth
3: short_ice_remove_middle_frames::fifth::{{closure}}
3: short_ice_remove_middle_frames::fifth::{closure#0}
[... omitted 4 frames ...]
4: short_ice_remove_middle_frames::second
5: short_ice_remove_middle_frames::first::{{closure}}
5: short_ice_remove_middle_frames::first::{closure#0}
6: short_ice_remove_middle_frames::first
7: short_ice_remove_middle_frames::main
8: core::ops::function::FnOnce::call_once
8: <fn() as core::ops::function::FnOnce<()>>::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

View file

@ -6,7 +6,7 @@
//
//@ run-fail
//@ error-pattern: Call to blocking function
//@ error-pattern: realtime_blocking::blocking::
//@ error-pattern: realtime_blocking::blocking
//@ ignore-backends: gcc
#![feature(sanitize)]