mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
rustc_codegen_utils: add harness for dumping/checking symbol names, and mw mangling impl.
This commit is contained in:
parent
e3315075f9
commit
0e5f27b169
16
Cargo.lock
16
Cargo.lock
@ -2699,6 +2699,7 @@ dependencies = [
|
||||
"rustc_metadata 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
"rustc_target 0.0.0",
|
||||
"std-mangle-rs 0.1.0 (git+https://github.com/michaelwoerister/std-mangle-rs?rev=2336dcdfcc91db3cdda18eda73aca488773ac6fc)",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
@ -3335,6 +3336,14 @@ dependencies = [
|
||||
"unwind 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "std-mangle-rs"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/michaelwoerister/std-mangle-rs?rev=2336dcdfcc91db3cdda18eda73aca488773ac6fc#2336dcdfcc91db3cdda18eda73aca488773ac6fc"
|
||||
dependencies = [
|
||||
"unic-idna-punycode 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.7.3"
|
||||
@ -3849,6 +3858,11 @@ name = "ucd-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unic-idna-punycode"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.4.0"
|
||||
@ -4354,6 +4368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
|
||||
"checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7"
|
||||
"checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa"
|
||||
"checksum std-mangle-rs 0.1.0 (git+https://github.com/michaelwoerister/std-mangle-rs?rev=2336dcdfcc91db3cdda18eda73aca488773ac6fc)" = "<none>"
|
||||
"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
|
||||
"checksum string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eea1eee654ef80933142157fdad9dd8bc43cf7c74e999e369263496f04ff4da"
|
||||
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
|
||||
@ -4397,6 +4412,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
"checksum unic-idna-punycode 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0366615c248bc56ea5ceafe6f71a682f6591e653b1ce61814999302617b8c0"
|
||||
"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
|
||||
|
@ -23,3 +23,7 @@ rustc_target = { path = "../librustc_target" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_metadata = { path = "../librustc_metadata" }
|
||||
rustc_mir = { path = "../librustc_mir" }
|
||||
|
||||
[dependencies.std-mangle-rs]
|
||||
git = "https://github.com/michaelwoerister/std-mangle-rs"
|
||||
rev = "2336dcdfcc91db3cdda18eda73aca488773ac6fc"
|
||||
|
@ -100,7 +100,9 @@ use syntax_pos::symbol::InternedString;
|
||||
|
||||
use log::debug;
|
||||
|
||||
mod dump;
|
||||
mod legacy;
|
||||
mod mw;
|
||||
mod v0;
|
||||
|
||||
pub fn provide(providers: &mut Providers<'_>) {
|
||||
@ -219,9 +221,19 @@ fn symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> Interne
|
||||
};
|
||||
|
||||
let mangled = match mangling_version {
|
||||
SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
|
||||
SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate, false),
|
||||
SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate, true),
|
||||
};
|
||||
|
||||
InternedString::intern(&mangled)
|
||||
let r = InternedString::intern(&mangled);
|
||||
|
||||
dump::record(
|
||||
tcx,
|
||||
instance,
|
||||
instantiating_crate,
|
||||
mangling_version,
|
||||
mangled,
|
||||
);
|
||||
|
||||
r
|
||||
}
|
||||
|
558
src/librustc_codegen_utils/symbol_names/dump.rs
Normal file
558
src/librustc_codegen_utils/symbol_names/dump.rs
Normal file
@ -0,0 +1,558 @@
|
||||
use rustc::hir::def_id::{CrateNum, DefId};
|
||||
use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
|
||||
use rustc::session::config::SymbolManglingVersion;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::print::{PrettyPrinter, Printer, Print};
|
||||
use rustc::ty::subst::{Kind, Subst, UnpackedKind};
|
||||
use rustc_mir::monomorphize::Instance;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{self, Write as FmtWrite};
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::ops::Range;
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use crate::symbol_names::{legacy, mw, v0};
|
||||
|
||||
thread_local!(static OUT_DIR: Option<PathBuf> = {
|
||||
std::env::var_os("RUST_SYMBOL_DUMP_DIR").map(PathBuf::from)
|
||||
});
|
||||
thread_local!(static OUTPUT: RefCell<Option<File>> = RefCell::new(None));
|
||||
|
||||
pub fn record(
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
instantiating_crate: Option<CrateNum>,
|
||||
mangling_version: SymbolManglingVersion,
|
||||
mangled: String,
|
||||
) {
|
||||
let header = "legacy+generics,legacy,mw,mw+compression,v0,v0+compression";
|
||||
|
||||
// Reuse the already-mangled symbol name that is used by codegen.
|
||||
let (legacy_mangling, v0_mangling_plus_compression) = match mangling_version {
|
||||
SymbolManglingVersion::Legacy =>
|
||||
(mangled, v0::mangle(tcx, instance, instantiating_crate, true)),
|
||||
SymbolManglingVersion::V0 =>
|
||||
(legacy::mangle(tcx, instance, instantiating_crate, false), mangled),
|
||||
};
|
||||
|
||||
// Always attempt all the choices of mangling.
|
||||
let legacy_mangling_plus_generics =
|
||||
legacy::mangle(tcx, instance, instantiating_crate, true);
|
||||
|
||||
let (mw_mangling, mw_mangling_plus_compression) =
|
||||
mw::mangle(tcx, instance, instantiating_crate)
|
||||
.unwrap_or((String::new(), String::new()));
|
||||
|
||||
let v0_mangling = v0::mangle(tcx, instance, instantiating_crate, false);
|
||||
|
||||
OUTPUT.with(|out| {
|
||||
let mut out = out.borrow_mut();
|
||||
if out.is_none() {
|
||||
OUT_DIR.with(|out_dir| {
|
||||
if let Some(out_dir) = out_dir {
|
||||
let mut opts = fs::OpenOptions::new();
|
||||
opts.write(true).create_new(true);
|
||||
|
||||
let mut time = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0);
|
||||
let mut file = loop {
|
||||
let file_path = out_dir.join(format!("{}-{}.{}.csv",
|
||||
tcx.crate_name,
|
||||
tcx.sess.local_crate_disambiguator(),
|
||||
time,
|
||||
));
|
||||
|
||||
match opts.open(&file_path) {
|
||||
Ok(file) => break file,
|
||||
Err(e) => {
|
||||
if e.kind() == std::io::ErrorKind::AlreadyExists {
|
||||
time += 1;
|
||||
continue;
|
||||
}
|
||||
bug!("can't open symbol dump file `{}`: {:?}",
|
||||
file_path.display(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
writeln!(file, "{}", header).unwrap();
|
||||
*out = Some(file);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if let Some(out) = out.as_mut() {
|
||||
writeln!(out, "{},{},{},{},{},{}",
|
||||
legacy_mangling_plus_generics,
|
||||
legacy_mangling,
|
||||
mw_mangling,
|
||||
mw_mangling_plus_compression,
|
||||
v0_mangling,
|
||||
v0_mangling_plus_compression,
|
||||
).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
let def_id = instance.def_id();
|
||||
// FIXME(eddyb) this should ideally not be needed.
|
||||
let substs =
|
||||
tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs);
|
||||
|
||||
// Build the expected output of demangling, via `ty::print`.
|
||||
let make_expected_demangling = |alternate| {
|
||||
let cx = DemanglingPrinter {
|
||||
tcx,
|
||||
out: String::new(),
|
||||
alternate,
|
||||
in_value: true,
|
||||
binders: vec![],
|
||||
};
|
||||
if instance.is_vtable_shim() {
|
||||
cx.path_append_ns(
|
||||
|cx| cx.print_def_path(def_id, substs),
|
||||
'S',
|
||||
0,
|
||||
"",
|
||||
).unwrap().out
|
||||
} else {
|
||||
cx.print_def_path(def_id, substs).unwrap().out
|
||||
}
|
||||
};
|
||||
|
||||
let expected_demangling_alt = make_expected_demangling(true);
|
||||
let expected_demangling = make_expected_demangling(false);
|
||||
|
||||
for mangling in &[&v0_mangling, &v0_mangling_plus_compression] {
|
||||
match rustc_demangle::try_demangle(mangling) {
|
||||
Ok(demangling) => {
|
||||
let demangling_alt = format!("{:#}", demangling);
|
||||
if demangling_alt.contains('?') {
|
||||
bug!("demangle(alt) printing failed for {:?}\n{:?}", mangling, demangling_alt);
|
||||
}
|
||||
assert_eq!(demangling_alt, expected_demangling_alt);
|
||||
|
||||
let demangling = format!("{}", demangling);
|
||||
if demangling.contains('?') {
|
||||
bug!("demangle printing failed for {:?}\n{:?}", mangling, demangling);
|
||||
}
|
||||
assert_eq!(demangling, expected_demangling);
|
||||
}
|
||||
Err(_) => bug!("try_demangle failed for {:?}", mangling),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BinderLevel {
|
||||
lifetime_depths: Range<u32>,
|
||||
}
|
||||
|
||||
// Our expectation of the output of demangling,
|
||||
// relying on `ty::print` / `PrettyPrinter`.
|
||||
struct DemanglingPrinter<'a, 'tcx> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
out: String,
|
||||
|
||||
/// Equivalent to `rustc-demangle`'s `{:#}` printing.
|
||||
alternate: bool,
|
||||
|
||||
in_value: bool,
|
||||
binders: Vec<BinderLevel>,
|
||||
}
|
||||
|
||||
impl fmt::Write for DemanglingPrinter<'_, '_> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.out.write_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl DemanglingPrinter<'_, '_> {
|
||||
fn path_append_ns(
|
||||
mut self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self, fmt::Error>,
|
||||
ns: char,
|
||||
disambiguator: u64,
|
||||
name: &str,
|
||||
) -> Result<Self, fmt::Error> {
|
||||
self = print_prefix(self)?;
|
||||
|
||||
if let 'A'..='Z' = ns {
|
||||
self.write_str("::{")?;
|
||||
match ns {
|
||||
'C' => self.write_str("closure")?,
|
||||
'S' => self.write_str("shim")?,
|
||||
_ => write!(self, "{}", ns)?,
|
||||
}
|
||||
if !name.is_empty() {
|
||||
write!(self, ":{}", name)?;
|
||||
}
|
||||
write!(self, "#{}", disambiguator)?;
|
||||
self.write_str("}")?;
|
||||
} else {
|
||||
if !name.is_empty() {
|
||||
self.write_str("::")?;
|
||||
self.write_str(&name)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn print_lifetime_at_depth(&mut self, depth: u64) -> Result<(), fmt::Error> {
|
||||
if depth < 26 {
|
||||
write!(self, "'{}", (b'a' + depth as u8) as char)
|
||||
} else {
|
||||
write!(self, "'_{}", depth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Printer<'tcx, 'tcx> for DemanglingPrinter<'_, 'tcx> {
|
||||
type Error = fmt::Error;
|
||||
|
||||
type Path = Self;
|
||||
type Region = Self;
|
||||
type Type = Self;
|
||||
type DynExistential = Self;
|
||||
type Const = Self;
|
||||
|
||||
fn tcx(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn print_impl_path(
|
||||
self,
|
||||
impl_def_id: DefId,
|
||||
substs: &'tcx [Kind<'tcx>],
|
||||
mut self_ty: Ty<'tcx>,
|
||||
mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
let mut param_env = self.tcx.param_env(impl_def_id)
|
||||
.with_reveal_all();
|
||||
if !substs.is_empty() {
|
||||
param_env = param_env.subst(self.tcx, substs);
|
||||
}
|
||||
|
||||
match &mut impl_trait_ref {
|
||||
Some(impl_trait_ref) => {
|
||||
assert_eq!(impl_trait_ref.self_ty(), self_ty);
|
||||
*impl_trait_ref =
|
||||
self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref);
|
||||
self_ty = impl_trait_ref.self_ty();
|
||||
}
|
||||
None => {
|
||||
self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty);
|
||||
}
|
||||
}
|
||||
|
||||
self.path_qualified(self_ty, impl_trait_ref)
|
||||
}
|
||||
|
||||
fn print_region(
|
||||
mut self,
|
||||
region: ty::Region<'_>,
|
||||
) -> Result<Self::Region, Self::Error> {
|
||||
match *region {
|
||||
ty::ReErased => write!(self, "'_")?,
|
||||
|
||||
ty::ReLateBound(debruijn, ty::BrAnon(i)) => {
|
||||
let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
|
||||
let depth = binder.lifetime_depths.start + i;
|
||||
self.print_lifetime_at_depth(depth as u64)?;
|
||||
}
|
||||
|
||||
_ => bug!("symbol_names::dump: non-erased region `{:?}`", region),
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn print_type(
|
||||
mut self,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Self::Type, Self::Error> {
|
||||
match ty.sty {
|
||||
// Mangled as paths (unlike `pretty_print_type`).
|
||||
ty::FnDef(def_id, substs) |
|
||||
ty::Opaque(def_id, substs) |
|
||||
ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) |
|
||||
ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) |
|
||||
ty::Closure(def_id, ty::ClosureSubsts { substs }) |
|
||||
ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
|
||||
self.print_def_path(def_id, substs)
|
||||
}
|
||||
|
||||
// Mangled as placeholders.
|
||||
ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) |
|
||||
ty::Infer(_) | ty::Error => {
|
||||
write!(self, "_")?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
// Demangled with explicit type for constants (`len` here).
|
||||
ty::Array(ty, len) if !self.alternate => {
|
||||
write!(self, "[")?;
|
||||
self = ty.print(self)?;
|
||||
write!(self, "; ")?;
|
||||
if let Some(n) = len.assert_usize(self.tcx()) {
|
||||
write!(self, "{}", n)?;
|
||||
} else {
|
||||
self = len.print(self)?;
|
||||
}
|
||||
write!(self, ": usize]")?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
// Demangled without anyparens.
|
||||
ty::Dynamic(data, r) => {
|
||||
let print_r = self.region_should_not_be_omitted(r);
|
||||
write!(self, "dyn ")?;
|
||||
self = data.print(self)?;
|
||||
if print_r {
|
||||
write!(self, " + ")?;
|
||||
self = r.print(self)?;
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
_ => self.pretty_print_type(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_dyn_existential(
|
||||
mut self,
|
||||
predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
|
||||
) -> Result<Self::DynExistential, Self::Error> {
|
||||
// Generate the main trait ref, including associated types.
|
||||
let mut first = true;
|
||||
|
||||
if let Some(principal) = predicates.principal() {
|
||||
self = self.print_def_path(principal.def_id, &[])?;
|
||||
|
||||
// Use a type that can't appear in defaults of type parameters.
|
||||
let dummy_self = self.tcx().mk_ty_infer(ty::FreshTy(0));
|
||||
let principal = principal.with_self_ty(self.tcx(), dummy_self);
|
||||
|
||||
let args = self.generic_args_to_print(
|
||||
self.tcx().generics_of(principal.def_id),
|
||||
principal.substs,
|
||||
);
|
||||
|
||||
// Don't print any regions if they're all erased.
|
||||
let print_regions = args.iter().any(|arg| {
|
||||
match arg.unpack() {
|
||||
UnpackedKind::Lifetime(r) => *r != ty::ReErased,
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
let mut args = args.iter().cloned().filter(|arg| {
|
||||
match arg.unpack() {
|
||||
UnpackedKind::Lifetime(_) => print_regions,
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
let mut projections = predicates.projection_bounds();
|
||||
|
||||
let arg0 = args.next();
|
||||
let projection0 = projections.next();
|
||||
if arg0.is_some() || projection0.is_some() {
|
||||
let args = arg0.into_iter().chain(args);
|
||||
let projections = projection0.into_iter().chain(projections);
|
||||
|
||||
self = self.generic_delimiters(|mut cx| {
|
||||
cx = cx.comma_sep(args)?;
|
||||
if arg0.is_some() && projection0.is_some() {
|
||||
write!(cx, ", ")?;
|
||||
}
|
||||
cx.comma_sep(projections)
|
||||
})?;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
for def_id in predicates.auto_traits() {
|
||||
if !first {
|
||||
write!(self, " + ")?;
|
||||
}
|
||||
first = false;
|
||||
|
||||
self = self.print_def_path(def_id, &[])?;
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn print_const(
|
||||
mut self,
|
||||
ct: &'tcx ty::Const<'tcx>,
|
||||
) -> Result<Self::Const, Self::Error> {
|
||||
if let ty::Uint(_) = ct.ty.sty {
|
||||
if let Some(bits) = ct.assert_bits(self.tcx, ty::ParamEnv::empty().and(ct.ty)) {
|
||||
write!(self, "{}", bits)?;
|
||||
} else {
|
||||
write!(self, "_")?;
|
||||
}
|
||||
} else {
|
||||
write!(self, "_")?;
|
||||
}
|
||||
|
||||
if !self.alternate {
|
||||
write!(self, ": ")?;
|
||||
self = ct.ty.print(self)?;
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn path_crate(
|
||||
mut self,
|
||||
cnum: CrateNum,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
|
||||
let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
|
||||
if !self.alternate {
|
||||
write!(self, "[{:x}]", fingerprint.to_smaller_hash())?;
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
fn path_qualified(
|
||||
self,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
self.generic_delimiters(|mut cx| {
|
||||
cx = self_ty.print(cx)?;
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
write!(cx, " as ")?;
|
||||
cx = trait_ref.print(cx)?;
|
||||
}
|
||||
Ok(cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn path_append_impl(
|
||||
self,
|
||||
_print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
_disambiguated_data: &DisambiguatedDefPathData,
|
||||
_self_ty: Ty<'tcx>,
|
||||
_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
unreachable!()
|
||||
}
|
||||
fn path_append(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
disambiguated_data: &DisambiguatedDefPathData,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
let ns = match disambiguated_data.data {
|
||||
DefPathData::ClosureExpr => 'C',
|
||||
_ => '_',
|
||||
};
|
||||
|
||||
let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str());
|
||||
let name = name.as_ref().map_or("", |s| &s[..]);
|
||||
|
||||
self.path_append_ns(
|
||||
print_prefix,
|
||||
ns,
|
||||
disambiguated_data.disambiguator as u64,
|
||||
name,
|
||||
)
|
||||
}
|
||||
fn path_generic_args(
|
||||
mut self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
args: &[Kind<'tcx>],
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
self = print_prefix(self)?;
|
||||
|
||||
// Don't print any regions if they're all erased.
|
||||
let print_regions = args.iter().any(|arg| {
|
||||
match arg.unpack() {
|
||||
UnpackedKind::Lifetime(r) => *r != ty::ReErased,
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
let args = args.iter().cloned().filter(|arg| {
|
||||
match arg.unpack() {
|
||||
UnpackedKind::Lifetime(_) => print_regions,
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
|
||||
if args.clone().next().is_some() {
|
||||
if self.in_value {
|
||||
write!(self, "::")?;
|
||||
}
|
||||
self.generic_delimiters(|cx| cx.comma_sep(args))
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrinter<'tcx, 'tcx> for DemanglingPrinter<'_, 'tcx> {
|
||||
fn region_should_not_be_omitted(
|
||||
&self,
|
||||
region: ty::Region<'_>,
|
||||
) -> bool {
|
||||
*region != ty::ReErased
|
||||
}
|
||||
|
||||
fn generic_delimiters(
|
||||
mut self,
|
||||
f: impl FnOnce(Self) -> Result<Self, Self::Error>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
write!(self, "<")?;
|
||||
let was_in_value = ::std::mem::replace(&mut self.in_value, false);
|
||||
self = f(self)?;
|
||||
self.in_value = was_in_value;
|
||||
write!(self, ">")?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn in_binder<T>(
|
||||
mut self,
|
||||
value: &ty::Binder<T>,
|
||||
) -> Result<Self, Self::Error>
|
||||
where T: Print<'tcx, 'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>
|
||||
{
|
||||
let regions = if value.has_late_bound_regions() {
|
||||
self.tcx.collect_referenced_late_bound_regions(value)
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let mut lifetime_depths =
|
||||
self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i);
|
||||
|
||||
let lifetimes = regions.into_iter().map(|br| {
|
||||
match br {
|
||||
ty::BrAnon(i) => i + 1,
|
||||
_ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
|
||||
}
|
||||
}).max().unwrap_or(0);
|
||||
|
||||
lifetime_depths.end += lifetimes;
|
||||
|
||||
if lifetimes > 0 {
|
||||
write!(self, "for<")?;
|
||||
for i in lifetime_depths.clone() {
|
||||
if i > lifetime_depths.start {
|
||||
write!(self, ", ")?;
|
||||
}
|
||||
self.print_lifetime_at_depth(i as u64)?;
|
||||
}
|
||||
write!(self, "> ")?;
|
||||
}
|
||||
|
||||
self.binders.push(BinderLevel { lifetime_depths });
|
||||
self = value.skip_binder().print(self)?;
|
||||
self.binders.pop();
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ pub(super) fn mangle(
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
instantiating_crate: Option<CrateNum>,
|
||||
include_generic_args: bool,
|
||||
) -> String {
|
||||
let def_id = instance.def_id();
|
||||
|
||||
@ -56,11 +57,17 @@ pub(super) fn mangle(
|
||||
|
||||
let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
|
||||
|
||||
let substs = if include_generic_args {
|
||||
// FIXME(eddyb) this should ideally not be needed.
|
||||
&tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs)[..]
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
let mut printer = SymbolPrinter {
|
||||
tcx,
|
||||
path: SymbolPath::new(),
|
||||
keep_within_component: false,
|
||||
}.print_def_path(def_id, &[]).unwrap();
|
||||
}.print_def_path(def_id, substs).unwrap();
|
||||
|
||||
if instance.is_vtable_shim() {
|
||||
let _ = printer.write_str("{{vtable-shim}}");
|
||||
|
370
src/librustc_codegen_utils/symbol_names/mw.rs
Normal file
370
src/librustc_codegen_utils/symbol_names/mw.rs
Normal file
@ -0,0 +1,370 @@
|
||||
use std_mangle_rs::{ast, compress::compress_ext};
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::{CrateNum, DefId};
|
||||
use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::print::{Printer, Print};
|
||||
use rustc::ty::subst::{Kind, UnpackedKind};
|
||||
use rustc_data_structures::base_n;
|
||||
use rustc_mir::monomorphize::Instance;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::ast::{IntTy, UintTy, FloatTy};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(super) struct Unsupported;
|
||||
|
||||
pub(super) fn mangle(
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
instantiating_crate: Option<CrateNum>,
|
||||
) -> Result<(String, String), Unsupported> {
|
||||
if instance.is_vtable_shim() {
|
||||
return Err(Unsupported);
|
||||
}
|
||||
|
||||
let symbol = ast::Symbol {
|
||||
name: SymbolPrinter { tcx }
|
||||
.print_def_path(instance.def_id(), instance.substs)?,
|
||||
instantiating_crate: instantiating_crate.map(|instantiating_crate| {
|
||||
let fingerprint = tcx.crate_disambiguator(instantiating_crate).to_fingerprint();
|
||||
Arc::new(ast::PathPrefix::CrateId {
|
||||
name: tcx.original_crate_name(instantiating_crate).to_string(),
|
||||
dis: base_n::encode(fingerprint.to_smaller_hash() as u128, 62),
|
||||
})
|
||||
}),
|
||||
};
|
||||
|
||||
let mut uncompressed = String::new();
|
||||
symbol.mangle(&mut uncompressed);
|
||||
|
||||
let (compressed_symbol, _) = compress_ext(&symbol);
|
||||
let mut compressed = String::new();
|
||||
compressed_symbol.mangle(&mut compressed);
|
||||
|
||||
Ok((uncompressed, compressed))
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct SymbolPrinter<'a, 'tcx> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
|
||||
type Error = Unsupported;
|
||||
|
||||
type Path = Arc<ast::AbsolutePath>;
|
||||
type Region = !;
|
||||
type Type = Arc<ast::Type>;
|
||||
type DynExistential = !;
|
||||
type Const = !;
|
||||
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn print_impl_path(
|
||||
self,
|
||||
impl_def_id: DefId,
|
||||
_substs: &[Kind<'tcx>],
|
||||
self_ty: Ty<'tcx>,
|
||||
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
let key = self.tcx.def_key(impl_def_id);
|
||||
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
|
||||
|
||||
self.path_append_impl(
|
||||
|cx| cx.print_def_path(parent_def_id, &[]),
|
||||
&key.disambiguated_data,
|
||||
self_ty,
|
||||
impl_trait_ref,
|
||||
)
|
||||
}
|
||||
|
||||
fn print_region(
|
||||
self,
|
||||
_region: ty::Region<'_>,
|
||||
) -> Result<Self::Region, Self::Error> {
|
||||
bug!("mw::print_region: should never be called")
|
||||
}
|
||||
|
||||
fn print_type(
|
||||
self,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Self::Type, Self::Error> {
|
||||
macro_rules! basic {
|
||||
($name:ident) => (ast::Type::BasicType(ast::BasicType::$name))
|
||||
}
|
||||
Ok(Arc::new(match ty.sty {
|
||||
ty::Bool => basic!(Bool),
|
||||
ty::Char => basic!(Char),
|
||||
ty::Str => basic!(Str),
|
||||
ty::Tuple(_) if ty.is_unit() => basic!(Unit),
|
||||
ty::Int(IntTy::I8) => basic!(I8),
|
||||
ty::Int(IntTy::I16) => basic!(I16),
|
||||
ty::Int(IntTy::I32) => basic!(I32),
|
||||
ty::Int(IntTy::I64) => basic!(I64),
|
||||
ty::Int(IntTy::I128) => basic!(I128),
|
||||
ty::Int(IntTy::Isize) => basic!(Isize),
|
||||
ty::Uint(UintTy::U8) => basic!(U8),
|
||||
ty::Uint(UintTy::U16) => basic!(U16),
|
||||
ty::Uint(UintTy::U32) => basic!(U32),
|
||||
ty::Uint(UintTy::U64) => basic!(U64),
|
||||
ty::Uint(UintTy::U128) => basic!(U128),
|
||||
ty::Uint(UintTy::Usize) => basic!(Usize),
|
||||
ty::Float(FloatTy::F32) => basic!(F32),
|
||||
ty::Float(FloatTy::F64) => basic!(F64),
|
||||
ty::Never => basic!(Never),
|
||||
|
||||
ty::Ref(_, ty, hir::MutImmutable) => ast::Type::Ref(ty.print(self)?),
|
||||
ty::Ref(_, ty, hir::MutMutable) => ast::Type::RefMut(ty.print(self)?),
|
||||
|
||||
ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::MutImmutable }) => {
|
||||
ast::Type::RawPtrConst(ty.print(self)?)
|
||||
}
|
||||
ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::MutMutable }) => {
|
||||
ast::Type::RawPtrMut(ty.print(self)?)
|
||||
}
|
||||
|
||||
ty::Array(ty, len) => {
|
||||
let len = len.assert_usize(self.tcx()).ok_or(Unsupported)?;
|
||||
ast::Type::Array(Some(len), ty.print(self)?)
|
||||
}
|
||||
ty::Slice(ty) => ast::Type::Array(None, ty.print(self)?),
|
||||
|
||||
ty::Tuple(tys) => {
|
||||
let tys = tys.iter()
|
||||
.map(|k| k.expect_ty().print(self))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
ast::Type::Tuple(tys)
|
||||
}
|
||||
|
||||
// Mangle all nominal types as paths.
|
||||
ty::Adt(&ty::AdtDef { did: def_id, .. }, substs) |
|
||||
ty::FnDef(def_id, substs) |
|
||||
ty::Opaque(def_id, substs) |
|
||||
ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) |
|
||||
ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) |
|
||||
ty::Closure(def_id, ty::ClosureSubsts { substs }) |
|
||||
ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
|
||||
ast::Type::Named(self.print_def_path(def_id, substs)?)
|
||||
}
|
||||
ty::Foreign(def_id) => {
|
||||
ast::Type::Named(self.print_def_path(def_id, &[])?)
|
||||
}
|
||||
|
||||
ty::Param(p) => ast::Type::GenericParam(ast::Ident {
|
||||
ident: p.name.to_string(),
|
||||
tag: ast::IdentTag::TypeNs,
|
||||
dis: ast::NumericDisambiguator(0),
|
||||
}),
|
||||
|
||||
ty::FnPtr(sig) => {
|
||||
let mut params = sig.inputs().skip_binder().iter()
|
||||
.map(|ty| ty.print(self))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
if sig.c_variadic() {
|
||||
params.push(Arc::new(basic!(Ellipsis)));
|
||||
}
|
||||
let output = *sig.output().skip_binder();
|
||||
let return_type = if output.is_unit() {
|
||||
None
|
||||
} else {
|
||||
Some(output.print(self)?)
|
||||
};
|
||||
ast::Type::Fn {
|
||||
is_unsafe: sig.unsafety() == hir::Unsafety::Unsafe,
|
||||
abi: match sig.abi() {
|
||||
Abi::Rust => ast::Abi::Rust,
|
||||
Abi::C => ast::Abi::C,
|
||||
_ => return Err(Unsupported),
|
||||
},
|
||||
params,
|
||||
return_type,
|
||||
}
|
||||
}
|
||||
|
||||
_ => return Err(Unsupported),
|
||||
}))
|
||||
}
|
||||
|
||||
fn print_dyn_existential(
|
||||
self,
|
||||
_predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
|
||||
) -> Result<Self::DynExistential, Self::Error> {
|
||||
Err(Unsupported)
|
||||
}
|
||||
|
||||
fn print_const(
|
||||
self,
|
||||
_ct: &'tcx ty::Const<'tcx>,
|
||||
) -> Result<Self::Const, Self::Error> {
|
||||
Err(Unsupported)
|
||||
}
|
||||
|
||||
fn path_crate(
|
||||
self,
|
||||
cnum: CrateNum,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
|
||||
let path = ast::PathPrefix::CrateId {
|
||||
name: self.tcx.original_crate_name(cnum).to_string(),
|
||||
dis: base_n::encode(fingerprint.to_smaller_hash() as u128, 62),
|
||||
};
|
||||
Ok(Arc::new(ast::AbsolutePath::Path {
|
||||
name: Arc::new(path),
|
||||
args: ast::GenericArgumentList::new_empty(),
|
||||
}))
|
||||
}
|
||||
fn path_qualified(
|
||||
self,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
assert!(trait_ref.is_some());
|
||||
let trait_ref = trait_ref.unwrap();
|
||||
|
||||
// This is a default method in the trait declaration.
|
||||
let path = ast::PathPrefix::TraitImpl {
|
||||
self_type: self_ty.print(self)?,
|
||||
impled_trait: Some(self.print_def_path(trait_ref.def_id, trait_ref.substs)?),
|
||||
dis: ast::NumericDisambiguator(0),
|
||||
};
|
||||
Ok(Arc::new(ast::AbsolutePath::Path {
|
||||
name: Arc::new(path),
|
||||
args: ast::GenericArgumentList::new_empty(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn path_append_impl(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
disambiguated_data: &DisambiguatedDefPathData,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
let path = ast::PathPrefix::TraitImpl {
|
||||
// HACK(eddyb) include the `impl` prefix into the path, by nesting
|
||||
// another `TraitImpl` node into the Self type of the `impl`, e.g.:
|
||||
// `foo::<impl Tr for X>::..` becomes `<<X as foo> as Tr>::...`.
|
||||
self_type: Arc::new(ast::Type::Named(Arc::new(ast::AbsolutePath::Path {
|
||||
name: Arc::new(ast::PathPrefix::TraitImpl {
|
||||
self_type: self_ty.print(self)?,
|
||||
impled_trait: Some(print_prefix(self)?),
|
||||
dis: ast::NumericDisambiguator(disambiguated_data.disambiguator as u64),
|
||||
}),
|
||||
args: ast::GenericArgumentList::new_empty(),
|
||||
}))),
|
||||
|
||||
impled_trait: match trait_ref {
|
||||
Some(trait_ref) => Some(
|
||||
self.print_def_path(trait_ref.def_id, trait_ref.substs)?
|
||||
),
|
||||
None => None,
|
||||
},
|
||||
dis: ast::NumericDisambiguator(0),
|
||||
};
|
||||
Ok(Arc::new(ast::AbsolutePath::Path {
|
||||
name: Arc::new(path),
|
||||
args: ast::GenericArgumentList::new_empty(),
|
||||
}))
|
||||
}
|
||||
fn path_append(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
disambiguated_data: &DisambiguatedDefPathData,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
let mut path = print_prefix(self)?;
|
||||
|
||||
let (prefix, ast_args) = match Arc::make_mut(&mut path) {
|
||||
ast::AbsolutePath::Path { name, args } => (name, args),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut ident = match disambiguated_data.data {
|
||||
DefPathData::ClosureExpr => String::new(),
|
||||
_ => disambiguated_data.data.get_opt_name().ok_or(Unsupported)?.to_string(),
|
||||
};
|
||||
|
||||
let tag = match disambiguated_data.data {
|
||||
DefPathData::ClosureExpr => ast::IdentTag::Closure,
|
||||
|
||||
/*DefPathData::ValueNs(..) |
|
||||
DefPathData::Ctor |
|
||||
DefPathData::Field(..) => ast::IdentTag::ValueNs,*/
|
||||
|
||||
// HACK(eddyb) rather than using `ValueNs` (see above), this
|
||||
// encodes the disambiguated category into the identifier, so it's
|
||||
// lossless (see the RFC for why we can't just do type vs value).
|
||||
_ => {
|
||||
let tag = {
|
||||
let discriminant = unsafe {
|
||||
::std::intrinsics::discriminant_value(&disambiguated_data.data)
|
||||
};
|
||||
assert!(discriminant < 26);
|
||||
|
||||
// Mix in the name to avoid making it too predictable.
|
||||
let mut d = (discriminant ^ 0x55) % 26;
|
||||
for (i, b) in ident.bytes().enumerate() {
|
||||
d = (d + i as u64 + b as u64) % 26;
|
||||
}
|
||||
|
||||
(b'A' + d as u8) as char
|
||||
};
|
||||
ident.push(tag);
|
||||
|
||||
ast::IdentTag::TypeNs
|
||||
}
|
||||
};
|
||||
|
||||
let dis = ast::NumericDisambiguator(disambiguated_data.disambiguator as u64);
|
||||
|
||||
let prefix = if !ast_args.is_empty() {
|
||||
Arc::new(ast::PathPrefix::AbsolutePath { path })
|
||||
} else {
|
||||
prefix.clone()
|
||||
};
|
||||
|
||||
Ok(Arc::new(ast::AbsolutePath::Path {
|
||||
name: Arc::new(ast::PathPrefix::Node {
|
||||
prefix: prefix.clone(),
|
||||
ident: ast::Ident { ident, tag, dis },
|
||||
}),
|
||||
args: ast::GenericArgumentList::new_empty(),
|
||||
}))
|
||||
}
|
||||
fn path_generic_args(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
args: &[Kind<'tcx>],
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
let mut path = print_prefix(self)?;
|
||||
|
||||
if args.is_empty() {
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
let ast_args = match Arc::make_mut(&mut path) {
|
||||
ast::AbsolutePath::Path { args, .. } => args,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if !ast_args.is_empty() {
|
||||
bug!("mw::path_generic_args({:?}): prefix already has generic args: {:#?}",
|
||||
args, path);
|
||||
}
|
||||
|
||||
for &arg in args {
|
||||
match arg.unpack() {
|
||||
UnpackedKind::Lifetime(_) => {}
|
||||
UnpackedKind::Type(ty) => {
|
||||
ast_args.0.push(ty.print(self)?);
|
||||
}
|
||||
UnpackedKind::Const(_) => return Err(Unsupported),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
}
|
@ -6,6 +6,10 @@ use std::path::Path;
|
||||
/// List of whitelisted sources for packages.
|
||||
const WHITELISTED_SOURCES: &[&str] = &[
|
||||
"\"registry+https://github.com/rust-lang/crates.io-index\"",
|
||||
|
||||
"\"git+https://github.com/michaelwoerister/std-mangle-rs?\
|
||||
rev=2336dcdfcc91db3cdda18eda73aca488773ac6fc#\
|
||||
2336dcdfcc91db3cdda18eda73aca488773ac6fc\"",
|
||||
];
|
||||
|
||||
/// Checks for external package sources.
|
||||
|
Loading…
Reference in New Issue
Block a user