Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Rust Symbol Mangling by default #85530

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1217,13 +1217,20 @@ pub trait PrettyPrinter<'tcx>:
}
p!(")");
}
ty::Adt(def, substs) if def.variants.is_empty() => {
p!(print_value_path(def.did, substs));
ty::Adt(def, _) if def.variants.is_empty() => {
self = self.typed_value(
|mut this| {
write!(this, "unreachable()")?;
Ok(this)
},
|this| this.print_type(ty),
": ",
)?;
}
ty::Adt(def, substs) => {
let variant_id =
contents.variant.expect("destructed const of adt without variant id");
let variant_def = &def.variants[variant_id];
let variant_idx =
contents.variant.expect("destructed const of adt without variant idx");
let variant_def = &def.variants[variant_idx];
p!(print_value_path(variant_def.def_id, substs));

match variant_def.ctor_kind {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ impl DebuggingOptions {
}

pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::V0)
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_symbol_mangling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#![feature(never_type)]
#![feature(nll)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![recursion_limit = "256"]

#[macro_use]
Expand Down
158 changes: 136 additions & 22 deletions compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use rustc_data_structures::base_n;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::print::{Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
Expand All @@ -11,6 +13,7 @@ use rustc_target::abi::Integer;
use rustc_target::spec::abi::Abi;

use std::fmt::Write;
use std::iter;
use std::ops::Range;

pub(super) fn mangle(
Expand Down Expand Up @@ -545,39 +548,150 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
}

fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
// We only mangle a typed value if the const can be evaluated.
let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all());
match ct.val {
ty::ConstKind::Value(_) => {}

// Placeholders (should be demangled as `_`).
// NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore
// a path), even for it we still need to encode a placeholder, as
// the path could refer back to e.g. an `impl` using the constant.
ty::ConstKind::Unevaluated(_)
| ty::ConstKind::Param(_)
| ty::ConstKind::Infer(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Error(_) => {
// Never cached (single-character).
self.push("p");
return Ok(self);
}
}

if let Some(&i) = self.compress.as_ref().and_then(|c| c.consts.get(&ct)) {
return self.print_backref(i);
}
let start = self.out.len();

let mut neg = false;
let val = match ct.ty.kind() {
ty::Uint(_) | ty::Bool | ty::Char => {
ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty)
}
ty::Int(ity) => {
ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty).and_then(|b| {
let val = Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(b) as i128;
match ct.ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
self = ct.ty.print(self)?;

let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty);

// Negative integer values are mangled using `n` as a "sign prefix".
if let ty::Int(ity) = ct.ty.kind() {
let val =
Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128;
if val < 0 {
neg = true;
self.push("n");
}
bits = val.unsigned_abs();
}

let _ = write!(self.out, "{:x}_", bits);
}

// HACK(eddyb) because `ty::Const` only supports sized values (for now),
// we can't use `deref_const` + supporting `str`, we have to specially
// handle `&str` and include both `&` ("R") and `str` ("e") prefixes.
ty::Ref(_, ty, hir::Mutability::Not) if *ty == self.tcx.types.str_ => {
self.push("R");
match ct.val {
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
// NOTE(eddyb) the following comment was kept from `ty::print::pretty`:
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
let slice =
data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
let s = std::str::from_utf8(slice).expect("non utf8 str from miri");

self.push("e");
// FIXME(eddyb) use a specialized hex-encoding loop.
for byte in s.bytes() {
let _ = write!(self.out, "{:02x}", byte);
}
self.push("_");
}

_ => {
bug!("symbol_names: unsupported `&str` constant: {:?}", ct);
}
}
}

ty::Ref(_, _, mutbl) => {
self.push(match mutbl {
hir::Mutability::Not => "R",
hir::Mutability::Mut => "Q",
});
self = self.tcx.deref_const(ty::ParamEnv::reveal_all().and(ct)).print(self)?;
}

ty::Array(..) | ty::Tuple(..) | ty::Adt(..) => {
let contents = self.tcx.destructure_const(ty::ParamEnv::reveal_all().and(ct));
let fields = contents.fields.iter().copied();

let print_field_list = |mut this: Self, prefix| {
this.push(prefix);
for field in fields.clone() {
this = field.print(this)?;
}
Some(val.unsigned_abs())
})
this.push("E");
Ok(this)
};

match *ct.ty.kind() {
ty::Array(..) => {
self = print_field_list(self, "A")?;
}
ty::Tuple(..) => {
self = print_field_list(self, "T")?;
}
ty::Adt(def, substs) => {
let variant_idx =
contents.variant.expect("destructed const of adt without variant idx");
let variant_def = &def.variants[variant_idx];

self.push("V");
self = self.print_def_path(variant_def.def_id, substs)?;

match variant_def.ctor_kind {
CtorKind::Const => {
self.push("u");
}
CtorKind::Fn => {
self = print_field_list(self, "T")?;
}
CtorKind::Fictive => {
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
// HACK(eddyb) this mimics `path_append`,
// instead of simply using `field_def.ident`,
// just to be able to handle disambiguators.
let disambiguated_field =
self.tcx.def_key(field_def.did).disambiguated_data;
let field_name =
disambiguated_field.data.get_opt_name().map(|s| s.as_str());
self.push_disambiguator(
disambiguated_field.disambiguator as u64,
);
self.push_ident(&field_name.as_ref().map_or("", |s| &s[..]));

self = field.print(self)?;
}
self.push("E");
}
}
}
_ => unreachable!(),
}
}

_ => {
bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
}
};

if let Some(bits) = val {
// We only print the type if the const can be evaluated.
self = ct.ty.print(self)?;
let _ = write!(self.out, "{}{:x}_", if neg { "n" } else { "" }, bits);
} else {
// NOTE(eddyb) despite having the path, we need to
// encode a placeholder, as the path could refer
// back to e.g. an `impl` using the constant.
self.push("p");
}

// Only cache consts that do not refer to an enclosing
Expand Down
2 changes: 1 addition & 1 deletion src/test/debuginfo/function-call.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// This test does not passed with gdb < 8.0. See #53497.
// min-gdb-version: 8.0
// min-gdb-version: 10.1

// compile-flags:-g

Expand Down
2 changes: 1 addition & 1 deletion src/test/debuginfo/function-names.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Function names are formatted differently in old versions of GDB
// min-gdb-version: 9.2
// min-gdb-version: 10.1

// compile-flags:-g

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:16:5
thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:21:5
stack backtrace:
0: std::panicking::begin_panic
1: issue_47429_short_backtraces::main
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/panics/issue-47429-short-backtraces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
// ignore-emscripten no panic or subprocess support
// ignore-sgx no subprocess support

// NOTE(eddyb) output differs between symbol mangling schemes
// revisions: legacy v0
// [legacy] compile-flags: -Zsymbol-mangling-version=legacy
// [v0] compile-flags: -Zsymbol-mangling-version=v0

fn main() {
panic!()
}
5 changes: 5 additions & 0 deletions src/test/ui/panics/issue-47429-short-backtraces.v0.run.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:21:5
stack backtrace:
0: std::panicking::begin_panic::<&str>
1: issue_47429_short_backtraces::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.