rustc_codegen_utils: add harness for dumping/checking symbol names, and mw mangling impl.

This commit is contained in:
Eduard-Mihai Burtescu 2019-05-30 00:42:56 +03:00
parent e3315075f9
commit 0e5f27b169
7 changed files with 974 additions and 3 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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
}

View 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)
}
}

View File

@ -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}}");

View 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)
}
}

View File

@ -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.