From e89890514149d31872ba486bbce2f762a2d99f88 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 30 May 2019 22:58:49 +0300 Subject: [PATCH 01/10] Update rustc-demangle version. --- Cargo.lock | 10 +++++----- src/librustc_codegen_llvm/Cargo.toml | 2 +- src/librustc_codegen_ssa/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bee0e0e2ad2f..81806b60635a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,7 +120,7 @@ dependencies = [ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -2492,7 +2492,7 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.10" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2648,7 +2648,7 @@ dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_llvm 0.0.0", ] @@ -2665,7 +2665,7 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_codegen_utils 0.0.0", @@ -4313,7 +4313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-serialize 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf09c60aaee892b0fd107544cfe607d8d463e7f33da34aa823566b8fd2b17f53" "checksum rustc-ap-syntax 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69f38cc120ff317678bbda8c4f58c1bbc1de64b615383ab01480482dde5e95a1" "checksum rustc-ap-syntax_pos 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20a0a201141c5c416b1924b079eeefc7b013e34ece0740ce4997f358b3684a7f" -"checksum rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "82ae957aa1b3055d8e086486723c0ccd3d7b8fa190ae8fa2e35543b6171c810e" +"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d98c51d9cbbe810c8b6693236d3412d8cd60513ff27a3e1b6af483dca0af544" "checksum rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363" diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index 841cf98164eb4..4ae8303c76d3c 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -13,7 +13,7 @@ test = false [dependencies] cc = "1.0.1" # Used to locate MSVC num_cpus = "1.0" -rustc-demangle = "0.1.4" +rustc-demangle = "0.1.15" rustc_llvm = { path = "../librustc_llvm" } memmap = "0.6" diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index af99d39182c24..0b34ec8e8bc1c 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -14,7 +14,7 @@ test = false bitflags = "1.0.4" cc = "1.0.1" num_cpus = "1.0" -rustc-demangle = "0.1.4" +rustc-demangle = "0.1.15" memmap = "0.6" log = "0.4.5" libc = "0.2.44" From 654d0596d3f21c8f774c95324bf79e5d6fbb75d4 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 29 May 2019 23:58:55 +0300 Subject: [PATCH 02/10] rustc_codegen_utils: test demangler output, not just symbol names. --- Cargo.lock | 1 + src/librustc_codegen_utils/Cargo.toml | 1 + .../symbol_names_test.rs | 8 +++-- src/test/ui/symbol-names/basic.rs | 5 ++- src/test/ui/symbol-names/basic.stderr | 16 ++++++++-- src/test/ui/symbol-names/impl1.rs | 10 ++++-- src/test/ui/symbol-names/impl1.stderr | 32 ++++++++++++++++--- src/test/ui/symbol-names/issue-60925.rs | 4 ++- src/test/ui/symbol-names/issue-60925.stderr | 14 +++++++- 9 files changed, 78 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81806b60635a3..5a981b3f08fef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2688,6 +2688,7 @@ dependencies = [ "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "rustc_metadata 0.0.0", "rustc_mir 0.0.0", diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index c75208b9e06c1..531c5abb14727 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -13,6 +13,7 @@ test = false [dependencies] flate2 = "1.0" log = "0.4" +rustc-demangle = "0.1.15" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs index 27ae0b97e5945..b935ccb7398e2 100644 --- a/src/librustc_codegen_utils/symbol_names_test.rs +++ b/src/librustc_codegen_utils/symbol_names_test.rs @@ -39,8 +39,12 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names let instance = Instance::mono(tcx, def_id); - let name = self.tcx.symbol_name(instance); - tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); + let mangled = self.tcx.symbol_name(instance); + tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); + if let Ok(demangling) = rustc_demangle::try_demangle(&mangled.as_str()) { + tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); + tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); + } } else if attr.check_name(DEF_PATH) { let path = tcx.def_path_str(def_id); tcx.sess.span_err(attr.span, &format!("def-path({})", path)); diff --git a/src/test/ui/symbol-names/basic.rs b/src/test/ui/symbol-names/basic.rs index 086b903b973b0..1459ac014ea35 100644 --- a/src/test/ui/symbol-names/basic.rs +++ b/src/test/ui/symbol-names/basic.rs @@ -1,6 +1,9 @@ #![feature(rustc_attrs)] -#[rustc_symbol_name] //~ ERROR _ZN5basic4main +#[rustc_symbol_name] +//~^ ERROR symbol-name(_ZN5basic4main +//~| ERROR demangling(basic::main +//~| ERROR demangling-alt(basic::main) #[rustc_def_path] //~ ERROR def-path(main) fn main() { } diff --git a/src/test/ui/symbol-names/basic.stderr b/src/test/ui/symbol-names/basic.stderr index 7539cbada8b7b..ebb8b4390d28d 100644 --- a/src/test/ui/symbol-names/basic.stderr +++ b/src/test/ui/symbol-names/basic.stderr @@ -4,11 +4,23 @@ error: symbol-name(_ZN5basic4main17hd72940ef9669d526E) LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ +error: demangling(basic::main::hd72940ef9669d526) + --> $DIR/basic.rs:3:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(basic::main) + --> $DIR/basic.rs:3:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + error: def-path(main) - --> $DIR/basic.rs:4:1 + --> $DIR/basic.rs:7:1 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index c712137e828f9..803fa856b60cf 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -5,7 +5,10 @@ mod foo { pub struct Foo { x: u32 } impl Foo { - #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar + #[rustc_symbol_name] + //~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar + //~| ERROR demangling(impl1::foo::Foo::bar + //~| ERROR demangling-alt(impl1::foo::Foo::bar) #[rustc_def_path] //~ ERROR def-path(foo::Foo::bar) fn bar() { } } @@ -15,7 +18,10 @@ mod bar { use foo::Foo; impl Foo { - #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz + #[rustc_symbol_name] + //~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz + //~| ERROR demangling(impl1::bar::::baz + //~| ERROR demangling-alt(impl1::bar::::baz) #[rustc_def_path] //~ ERROR def-path(bar::::baz) fn baz() { } } diff --git a/src/test/ui/symbol-names/impl1.stderr b/src/test/ui/symbol-names/impl1.stderr index 20e48782a3a9e..3a7d540c4882d 100644 --- a/src/test/ui/symbol-names/impl1.stderr +++ b/src/test/ui/symbol-names/impl1.stderr @@ -4,23 +4,47 @@ error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE) LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ +error: demangling(impl1::foo::Foo::bar::he53b9bee7600ed8d) + --> $DIR/impl1.rs:8:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(impl1::foo::Foo::bar) + --> $DIR/impl1.rs:8:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + error: def-path(foo::Foo::bar) - --> $DIR/impl1.rs:9:9 + --> $DIR/impl1.rs:12:9 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E) - --> $DIR/impl1.rs:18:9 + --> $DIR/impl1.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(impl1::bar::::baz::h86c41f0462d901d4) + --> $DIR/impl1.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(impl1::bar::::baz) + --> $DIR/impl1.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: def-path(bar::::baz) - --> $DIR/impl1.rs:19:9 + --> $DIR/impl1.rs:25:9 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 8 previous errors diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs index e9f763ad7cf67..22efa978bd2b6 100644 --- a/src/test/ui/symbol-names/issue-60925.rs +++ b/src/test/ui/symbol-names/issue-60925.rs @@ -14,7 +14,9 @@ mod foo { impl Foo<::llvm::Foo> { #[rustc_symbol_name] -//~^ ERROR _ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo17h059a991a004536adE + //~^ ERROR symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo + //~| ERROR demangling(issue_60925::foo::Foo $DIR/issue-60925.rs:16:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(issue_60925::foo::Foo $DIR/issue-60925.rs:16:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors From 2092963a1851efca5222bd816557055988ce8f90 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 29 Jan 2019 07:24:32 +0200 Subject: [PATCH 03/10] rustc_codegen_utils: add new mangling scheme implementation. --- Cargo.lock | 7 + src/librustc/query/mod.rs | 4 + src/librustc/session/config.rs | 38 +- src/librustc/ty/query/mod.rs | 2 +- src/librustc_codegen_utils/Cargo.toml | 1 + src/librustc_codegen_utils/lib.rs | 2 + src/librustc_codegen_utils/symbol_names.rs | 546 ++------------ .../symbol_names/legacy.rs | 463 ++++++++++++ src/librustc_codegen_utils/symbol_names/v0.rs | 664 ++++++++++++++++++ src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/encoder.rs | 1 + src/librustc_metadata/schema.rs | 2 + 12 files changed, 1241 insertions(+), 490 deletions(-) create mode 100644 src/librustc_codegen_utils/symbol_names/legacy.rs create mode 100644 src/librustc_codegen_utils/symbol_names/v0.rs diff --git a/Cargo.lock b/Cargo.lock index 5a981b3f08fef..a13bc0e74760a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2023,6 +2023,11 @@ dependencies = [ "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "punycode" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quick-error" version = "1.2.2" @@ -2687,6 +2692,7 @@ version = "0.0.0" dependencies = [ "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", @@ -4277,6 +4283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24f5844db2f839e97e3021980975f6ebf8691d9b9b2ca67ed3feb38dc3edb52c" "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" "checksum pulldown-cmark 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "051e60ace841b3bfecd402fe5051c06cb3bec4a6e6fdd060a37aa8eb829a1db3" +"checksum punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ddd112cca70a4d30883b2d21568a1d376ff8be4758649f64f973c6845128ad3" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 81aa8d434d37f..f61677fa59499 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -624,6 +624,10 @@ rustc_queries! { fatal_cycle desc { "test whether a crate has #![no_builtins]" } } + query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { + fatal_cycle + desc { "query a crate's symbol mangling version" } + } query extern_crate(_: DefId) -> Option<&'tcx ExternCrate> { eval_always diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 300d0cbfba55b..d8efa17defe3d 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -131,6 +131,14 @@ impl SwitchWithOptPath { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +pub enum SymbolManglingVersion { + Legacy, + V0, +} + +impl_stable_hash_via_hash!(SymbolManglingVersion); + #[derive(Clone, Copy, PartialEq, Hash)] pub enum DebugInfo { None, @@ -838,11 +846,14 @@ macro_rules! options { Some("an optional path to the profiling data output directory"); pub const parse_merge_functions: Option<&str> = Some("one of: `disabled`, `trampolines`, or `aliases`"); + pub const parse_symbol_mangling_version: Option<&str> = + Some("either `legacy` or `v0` (RFC 2603)"); } #[allow(dead_code)] mod $mod_set { - use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath}; + use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath, + SymbolManglingVersion}; use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; use std::path::PathBuf; use std::str::FromStr; @@ -1112,6 +1123,18 @@ macro_rules! options { } true } + + fn parse_symbol_mangling_version( + slot: &mut SymbolManglingVersion, + v: Option<&str>, + ) -> bool { + *slot = match v { + Some("legacy") => SymbolManglingVersion::Legacy, + Some("v0") => SymbolManglingVersion::V0, + _ => return false, + }; + true + } } ) } @@ -1457,6 +1480,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "only allow the listed language features to be enabled in code (space separated)"), emit_artifact_notifications: bool = (false, parse_bool, [UNTRACKED], "emit notifications after each artifact has been output (only in the JSON format)"), + symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy, + parse_symbol_mangling_version, [TRACKED], + "which mangling version to use for symbol names"), } pub fn default_lib_output() -> CrateType { @@ -2551,7 +2577,8 @@ mod dep_tracking { use std::path::PathBuf; use std::collections::hash_map::DefaultHasher; use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes, - Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath}; + Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath, + SymbolManglingVersion}; use syntax::feature_gate::UnstableFeatures; use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple}; use syntax::edition::Edition; @@ -2620,6 +2647,7 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(Edition); impl_dep_tracking_hash_via_hash!(LinkerPluginLto); impl_dep_tracking_hash_via_hash!(SwitchWithOptPath); + impl_dep_tracking_hash_via_hash!(SymbolManglingVersion); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); @@ -2693,7 +2721,7 @@ mod tests { use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; use std::path::PathBuf; - use super::{Externs, OutputType, OutputTypes}; + use super::{Externs, OutputType, OutputTypes, SymbolManglingVersion}; use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel}; use syntax::symbol::sym; use syntax::edition::{Edition, DEFAULT_EDITION}; @@ -3367,6 +3395,10 @@ mod tests { opts = reference.clone(); opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + + opts = reference.clone(); + opts.debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0; + assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); } #[test] diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index be52b7e645198..a2bced97102a6 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -20,7 +20,7 @@ use crate::mir::mono::CodegenUnit; use crate::mir; use crate::mir::interpret::GlobalId; use crate::session::CrateDisambiguator; -use crate::session::config::{EntryFnType, OutputFilenames, OptLevel}; +use crate::session::config::{EntryFnType, OutputFilenames, OptLevel, SymbolManglingVersion}; use crate::traits::{self, Vtable}; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 531c5abb14727..268be2b109114 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -13,6 +13,7 @@ test = false [dependencies] flate2 = "1.0" log = "0.4" +punycode = "0.4.0" rustc-demangle = "0.1.15" syntax = { path = "../libsyntax" } diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index b4ba90c61f650..ea1d08354528b 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -7,7 +7,9 @@ #![feature(arbitrary_self_types)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(core_intrinsics)] #![feature(custom_attribute)] +#![feature(never_type)] #![feature(nll)] #![allow(unused_attributes)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 4a5d356096eec..134cbaaa3b398 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -87,18 +87,12 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::hir::Node; use rustc::hir::CodegenFnAttrFlags; -use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; -use rustc::ich::NodeIdHashingMode; -use rustc::ty::print::{PrettyPrinter, Printer, Print}; +use rustc::session::config::SymbolManglingVersion; use rustc::ty::query::Providers; -use rustc::ty::subst::{Kind, SubstsRef, UnpackedKind}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::mir::interpret::{ConstValue, Scalar}; -use rustc::util::common::record_time; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc::ty::{self, TyCtxt}; use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt}; use rustc_mir::monomorphize::Instance; @@ -106,129 +100,20 @@ use syntax_pos::symbol::InternedString; use log::debug; -use std::fmt::{self, Write}; -use std::mem::{self, discriminant}; +mod legacy; +mod v0; pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { - symbol_name, + symbol_name: |tcx, instance| ty::SymbolName { + name: symbol_name(tcx, instance), + }, ..*providers }; } -fn get_symbol_hash<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - - // the DefId of the item this name is for - def_id: DefId, - - // instance this name will be for - instance: Instance<'tcx>, - - // type of the item, without any generic - // parameters substituted; this is - // included in the hash as a kind of - // safeguard. - item_type: Ty<'tcx>, - - // values for generic type parameters, - // if any. - substs: SubstsRef<'tcx>, -) -> u64 { - debug!( - "get_symbol_hash(def_id={:?}, parameters={:?})", - def_id, substs - ); - - let mut hasher = StableHasher::::new(); - let mut hcx = tcx.create_stable_hashing_context(); - - record_time(&tcx.sess.perf_stats.symbol_hash_time, || { - // the main symbol name is not necessarily unique; hash in the - // compiler's internal def-path, guaranteeing each symbol has a - // truly unique path - tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); - - // Include the main item-type. Note that, in this case, the - // assertions about `needs_subst` may not hold, but this item-type - // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); - hcx.while_hashing_spans(false, |hcx| { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - item_type.hash_stable(hcx, &mut hasher); - }); - }); - - // If this is a function, we hash the signature as well. - // This is not *strictly* needed, but it may help in some - // situations, see the `run-make/a-b-a-linker-guard` test. - if let ty::FnDef(..) = item_type.sty { - item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher); - } - - // also include any type parameters (for generic items) - assert!(!substs.has_erasable_regions()); - assert!(!substs.needs_subst()); - substs.hash_stable(&mut hcx, &mut hasher); - - let is_generic = substs.non_erasable_generics().next().is_some(); - let avoid_cross_crate_conflicts = - // If this is an instance of a generic function, we also hash in - // the ID of the instantiating crate. This avoids symbol conflicts - // in case the same instances is emitted in two crates of the same - // project. - is_generic || - - // If we're dealing with an instance of a function that's inlined from - // another crate but we're marking it as globally shared to our - // compliation (aka we're not making an internal copy in each of our - // codegen units) then this symbol may become an exported (but hidden - // visibility) symbol. This means that multiple crates may do the same - // and we want to be sure to avoid any symbol conflicts here. - match MonoItem::Fn(instance).instantiation_mode(tcx) { - InstantiationMode::GloballyShared { may_conflict: true } => true, - _ => false, - }; - - if avoid_cross_crate_conflicts { - let instantiating_crate = if is_generic { - if !def_id.is_local() && tcx.sess.opts.share_generics() { - // If we are re-using a monomorphization from another crate, - // we have to compute the symbol hash accordingly. - let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id); - - upstream_monomorphizations - .and_then(|monos| monos.get(&substs).cloned()) - .unwrap_or(LOCAL_CRATE) - } else { - LOCAL_CRATE - } - } else { - LOCAL_CRATE - }; - - (&tcx.original_crate_name(instantiating_crate).as_str()[..]) - .hash_stable(&mut hcx, &mut hasher); - (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher); - } - - // We want to avoid accidental collision between different types of instances. - // Especially, VtableShim may overlap with its original instance without this. - discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher); - }); - - // 64 bits should be enough to avoid collisions. - hasher.finish() -} - -fn symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> ty::SymbolName { - ty::SymbolName { - name: compute_symbol_name(tcx, instance), - } -} - -fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> InternedString { +fn symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> InternedString { let def_id = instance.def_id(); let substs = instance.substs; @@ -278,376 +163,65 @@ fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> return tcx.item_name(def_id).as_interned_str(); } - // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. - let mut ty_def_id = def_id; - let instance_ty; - loop { - let key = tcx.def_key(ty_def_id); - match key.disambiguated_data.data { - DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = tcx.type_of(ty_def_id); - break; - } - _ => { - // if we're making a symbol for something, there ought - // to be a value or type-def or something in there - // *somewhere* - ty_def_id.index = key.parent.unwrap_or_else(|| { - bug!( - "finding type for {:?}, encountered def-id {:?} with no \ - parent", - def_id, - ty_def_id - ); - }); - } - } - } - // Erase regions because they may not be deterministic when hashed - // and should not matter anyhow. - let instance_ty = tcx.erase_regions(&instance_ty); + let is_generic = substs.non_erasable_generics().next().is_some(); + let avoid_cross_crate_conflicts = + // If this is an instance of a generic function, we also hash in + // the ID of the instantiating crate. This avoids symbol conflicts + // in case the same instances is emitted in two crates of the same + // project. + is_generic || - let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs); - - let mut printer = SymbolPrinter { - tcx, - path: SymbolPath::new(), - keep_within_component: false, - }.print_def_path(def_id, &[]).unwrap(); - - if instance.is_vtable_shim() { - let _ = printer.write_str("{{vtable-shim}}"); - } - - InternedString::intern(&printer.path.finish(hash)) -} - -// Follow C++ namespace-mangling style, see -// http://en.wikipedia.org/wiki/Name_mangling for more info. -// -// It turns out that on macOS you can actually have arbitrary symbols in -// function names (at least when given to LLVM), but this is not possible -// when using unix's linker. Perhaps one day when we just use a linker from LLVM -// we won't need to do this name mangling. The problem with name mangling is -// that it seriously limits the available characters. For example we can't -// have things like &T in symbol names when one would theoretically -// want them for things like impls of traits on that type. -// -// To be able to work on all platforms and get *some* reasonable output, we -// use C++ name-mangling. -#[derive(Debug)] -struct SymbolPath { - result: String, - temp_buf: String, -} - -impl SymbolPath { - fn new() -> Self { - let mut result = SymbolPath { - result: String::with_capacity(64), - temp_buf: String::with_capacity(16), + // If we're dealing with an instance of a function that's inlined from + // another crate but we're marking it as globally shared to our + // compliation (aka we're not making an internal copy in each of our + // codegen units) then this symbol may become an exported (but hidden + // visibility) symbol. This means that multiple crates may do the same + // and we want to be sure to avoid any symbol conflicts here. + match MonoItem::Fn(instance).instantiation_mode(tcx) { + InstantiationMode::GloballyShared { may_conflict: true } => true, + _ => false, }; - result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested - result - } - - fn finalize_pending_component(&mut self) { - if !self.temp_buf.is_empty() { - let _ = write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf); - self.temp_buf.clear(); - } - } - - fn finish(mut self, hash: u64) -> String { - self.finalize_pending_component(); - // E = end name-sequence - let _ = write!(self.result, "17h{:016x}E", hash); - self.result - } -} - -struct SymbolPrinter<'a, 'tcx> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - path: SymbolPath, - - // When `true`, `finalize_pending_component` isn't used. - // This is needed when recursing into `path_qualified`, - // or `path_generic_args`, as any nested paths are - // logically within one component. - keep_within_component: bool, -} - -// HACK(eddyb) this relies on using the `fmt` interface to get -// `PrettyPrinter` aka pretty printing of e.g. types in paths, -// symbol names should have their own printing machinery. - -impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, '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_region( - self, - _region: ty::Region<'_>, - ) -> Result { - Ok(self) - } - - fn print_type( - self, - ty: Ty<'tcx>, - ) -> Result { - match ty.sty { - // Print all nominal types 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) - } - _ => self.pretty_print_type(ty), - } - } - - fn print_dyn_existential( - mut self, - predicates: &'tcx ty::List>, - ) -> Result { - let mut first = true; - for p in predicates { - if !first { - write!(self, "+")?; - } - first = false; - self = p.print(self)?; - } - Ok(self) - } - fn print_const( - mut self, - ct: &'tcx ty::Const<'tcx>, - ) -> Result { - // only print integers - if let ConstValue::Scalar(Scalar::Raw { .. }) = ct.val { - if ct.ty.is_integral() { - return self.pretty_print_const(ct); - } - } - self.write_str("_")?; - Ok(self) - } - - fn path_crate( - mut self, - cnum: CrateNum, - ) -> Result { - self.write_str(&self.tcx.original_crate_name(cnum).as_str())?; - Ok(self) - } - fn path_qualified( - self, - self_ty: Ty<'tcx>, - trait_ref: Option>, - ) -> Result { - // Similar to `pretty_path_qualified`, but for the other - // types that are printed as paths (see `print_type` above). - match self_ty.sty { - ty::FnDef(..) | - ty::Opaque(..) | - ty::Projection(_) | - ty::UnnormalizedProjection(_) | - ty::Closure(..) | - ty::Generator(..) - if trait_ref.is_none() => - { - self.print_type(self_ty) - } - - _ => self.pretty_path_qualified(self_ty, trait_ref) - } - } + let instantiating_crate = if avoid_cross_crate_conflicts { + Some(if is_generic { + if !def_id.is_local() && tcx.sess.opts.share_generics() { + // If we are re-using a monomorphization from another crate, + // we have to compute the symbol hash accordingly. + let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id); - fn path_append_impl( - self, - print_prefix: impl FnOnce(Self) -> Result, - _disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option>, - ) -> Result { - self.pretty_path_append_impl( - |mut cx| { - cx = print_prefix(cx)?; - - if cx.keep_within_component { - // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it. - cx.write_str("::")?; - } else { - cx.path.finalize_pending_component(); - } - - Ok(cx) - }, - self_ty, - trait_ref, - ) - } - fn path_append( - mut self, - print_prefix: impl FnOnce(Self) -> Result, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result { - self = print_prefix(self)?; - - // Skip `::{{constructor}}` on tuple/unit structs. - match disambiguated_data.data { - DefPathData::Ctor => return Ok(self), - _ => {} - } - - if self.keep_within_component { - // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it. - self.write_str("::")?; - } else { - self.path.finalize_pending_component(); - } - - self.write_str(&disambiguated_data.data.as_interned_str().as_str())?; - Ok(self) - } - fn path_generic_args( - mut self, - print_prefix: impl FnOnce(Self) -> Result, - args: &[Kind<'tcx>], - ) -> Result { - self = print_prefix(self)?; - - let args = args.iter().cloned().filter(|arg| { - match arg.unpack() { - UnpackedKind::Lifetime(_) => false, - _ => true, + upstream_monomorphizations + .and_then(|monos| monos.get(&substs).cloned()) + .unwrap_or(LOCAL_CRATE) + } else { + LOCAL_CRATE } - }); - - if args.clone().next().is_some() { - self.generic_delimiters(|cx| cx.comma_sep(args)) } else { - Ok(self) - } - } -} - -impl PrettyPrinter<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { - fn region_should_not_be_omitted( - &self, - _region: ty::Region<'_>, - ) -> bool { - false - } - fn comma_sep( - mut self, - mut elems: impl Iterator, - ) -> Result - where T: Print<'tcx, 'tcx, Self, Output = Self, Error = Self::Error> - { - if let Some(first) = elems.next() { - self = first.print(self)?; - for elem in elems { - self.write_str(",")?; - self = elem.print(self)?; - } - } - Ok(self) - } - - fn generic_delimiters( - mut self, - f: impl FnOnce(Self) -> Result, - ) -> Result { - write!(self, "<")?; - - let kept_within_component = - mem::replace(&mut self.keep_within_component, true); - self = f(self)?; - self.keep_within_component = kept_within_component; - - write!(self, ">")?; - - Ok(self) - } -} - -impl fmt::Write for SymbolPrinter<'_, '_> { - fn write_str(&mut self, s: &str) -> fmt::Result { - // Name sanitation. LLVM will happily accept identifiers with weird names, but - // gas doesn't! - // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ - // NVPTX assembly has more strict naming rules than gas, so additionally, dots - // are replaced with '$' there. - - for c in s.chars() { - if self.path.temp_buf.is_empty() { - match c { - 'a'..='z' | 'A'..='Z' | '_' => {} - _ => { - // Underscore-qualify anything that didn't start as an ident. - self.path.temp_buf.push('_'); - } - } - } - match c { - // Escape these with $ sequences - '@' => self.path.temp_buf.push_str("$SP$"), - '*' => self.path.temp_buf.push_str("$BP$"), - '&' => self.path.temp_buf.push_str("$RF$"), - '<' => self.path.temp_buf.push_str("$LT$"), - '>' => self.path.temp_buf.push_str("$GT$"), - '(' => self.path.temp_buf.push_str("$LP$"), - ')' => self.path.temp_buf.push_str("$RP$"), - ',' => self.path.temp_buf.push_str("$C$"), - - '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => { - // NVPTX doesn't support these characters in symbol names. - self.path.temp_buf.push('$') - } - - // '.' doesn't occur in types and functions, so reuse it - // for ':' and '-' - '-' | ':' => self.path.temp_buf.push('.'), - - // Avoid segmentation fault on some platforms, see #60925. - 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$6d$"), + LOCAL_CRATE + }) + } else { + None + }; - // These are legal symbols - 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c), + // Pick the crate responsible for the symbol mangling version, which has to: + // 1. be stable for each instance, whether it's being defined or imported + // 2. obey each crate's own `-Z symbol-mangling-version`, as much as possible + // We solve these as follows: + // 1. because symbol names depend on both `def_id` and `instantiating_crate`, + // both their `CrateNum`s are stable for any given instance, so we can pick + // either and have a stable choice of symbol mangling version + // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) + let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); + let mangling_version = if mangling_version_crate == LOCAL_CRATE { + tcx.sess.opts.debugging_opts.symbol_mangling_version + } else { + tcx.symbol_mangling_version(mangling_version_crate) + }; - _ => { - self.path.temp_buf.push('$'); - for c in c.escape_unicode().skip(1) { - match c { - '{' => {} - '}' => self.path.temp_buf.push('$'), - c => self.path.temp_buf.push(c), - } - } - } - } - } + let mangled = match mangling_version { + SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), + SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate, true), + }; - Ok(()) - } + InternedString::intern(&mangled) } diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs new file mode 100644 index 0000000000000..53682b9bdc2c8 --- /dev/null +++ b/src/librustc_codegen_utils/symbol_names/legacy.rs @@ -0,0 +1,463 @@ +use rustc::hir::def_id::CrateNum; +use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; +use rustc::ich::NodeIdHashingMode; +use rustc::mir::interpret::{ConstValue, Scalar}; +use rustc::ty::print::{PrettyPrinter, Printer, Print}; +use rustc::ty::subst::{Kind, UnpackedKind}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::util::common::record_time; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_mir::monomorphize::Instance; + +use log::debug; + +use std::fmt::{self, Write}; +use std::mem::{self, discriminant}; + +pub(super) fn mangle( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + instance: Instance<'tcx>, + instantiating_crate: Option, +) -> String { + let def_id = instance.def_id(); + + // We want to compute the "type" of this item. Unfortunately, some + // kinds of items (e.g., closures) don't have an entry in the + // item-type array. So walk back up the find the closest parent + // that DOES have an entry. + let mut ty_def_id = def_id; + let instance_ty; + loop { + let key = tcx.def_key(ty_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { + instance_ty = tcx.type_of(ty_def_id); + break; + } + _ => { + // if we're making a symbol for something, there ought + // to be a value or type-def or something in there + // *somewhere* + ty_def_id.index = key.parent.unwrap_or_else(|| { + bug!( + "finding type for {:?}, encountered def-id {:?} with no \ + parent", + def_id, + ty_def_id + ); + }); + } + } + } + + // Erase regions because they may not be deterministic when hashed + // and should not matter anyhow. + let instance_ty = tcx.erase_regions(&instance_ty); + + let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); + + let mut printer = SymbolPrinter { + tcx, + path: SymbolPath::new(), + keep_within_component: false, + }.print_def_path(def_id, &[]).unwrap(); + + if instance.is_vtable_shim() { + let _ = printer.write_str("{{vtable-shim}}"); + } + + printer.path.finish(hash) +} + +fn get_symbol_hash<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + + // instance this name will be for + instance: Instance<'tcx>, + + // type of the item, without any generic + // parameters substituted; this is + // included in the hash as a kind of + // safeguard. + item_type: Ty<'tcx>, + + instantiating_crate: Option, +) -> u64 { + let def_id = instance.def_id(); + let substs = instance.substs; + debug!( + "get_symbol_hash(def_id={:?}, parameters={:?})", + def_id, substs + ); + + let mut hasher = StableHasher::::new(); + let mut hcx = tcx.create_stable_hashing_context(); + + record_time(&tcx.sess.perf_stats.symbol_hash_time, || { + // the main symbol name is not necessarily unique; hash in the + // compiler's internal def-path, guaranteeing each symbol has a + // truly unique path + tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); + + // Include the main item-type. Note that, in this case, the + // assertions about `needs_subst` may not hold, but this item-type + // ought to be the same for every reference anyway. + assert!(!item_type.has_erasable_regions()); + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + item_type.hash_stable(hcx, &mut hasher); + }); + }); + + // If this is a function, we hash the signature as well. + // This is not *strictly* needed, but it may help in some + // situations, see the `run-make/a-b-a-linker-guard` test. + if let ty::FnDef(..) = item_type.sty { + item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher); + } + + // also include any type parameters (for generic items) + assert!(!substs.has_erasable_regions()); + assert!(!substs.needs_subst()); + substs.hash_stable(&mut hcx, &mut hasher); + + if let Some(instantiating_crate) = instantiating_crate { + (&tcx.original_crate_name(instantiating_crate).as_str()[..]) + .hash_stable(&mut hcx, &mut hasher); + (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher); + } + + // We want to avoid accidental collision between different types of instances. + // Especially, VtableShim may overlap with its original instance without this. + discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher); + }); + + // 64 bits should be enough to avoid collisions. + hasher.finish() +} + +// Follow C++ namespace-mangling style, see +// http://en.wikipedia.org/wiki/Name_mangling for more info. +// +// It turns out that on macOS you can actually have arbitrary symbols in +// function names (at least when given to LLVM), but this is not possible +// when using unix's linker. Perhaps one day when we just use a linker from LLVM +// we won't need to do this name mangling. The problem with name mangling is +// that it seriously limits the available characters. For example we can't +// have things like &T in symbol names when one would theoretically +// want them for things like impls of traits on that type. +// +// To be able to work on all platforms and get *some* reasonable output, we +// use C++ name-mangling. +#[derive(Debug)] +struct SymbolPath { + result: String, + temp_buf: String, +} + +impl SymbolPath { + fn new() -> Self { + let mut result = SymbolPath { + result: String::with_capacity(64), + temp_buf: String::with_capacity(16), + }; + result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested + result + } + + fn finalize_pending_component(&mut self) { + if !self.temp_buf.is_empty() { + let _ = write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf); + self.temp_buf.clear(); + } + } + + fn finish(mut self, hash: u64) -> String { + self.finalize_pending_component(); + // E = end name-sequence + let _ = write!(self.result, "17h{:016x}E", hash); + self.result + } +} + +struct SymbolPrinter<'a, 'tcx> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + path: SymbolPath, + + // When `true`, `finalize_pending_component` isn't used. + // This is needed when recursing into `path_qualified`, + // or `path_generic_args`, as any nested paths are + // logically within one component. + keep_within_component: bool, +} + +// HACK(eddyb) this relies on using the `fmt` interface to get +// `PrettyPrinter` aka pretty printing of e.g. types in paths, +// symbol names should have their own printing machinery. + +impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, '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_region( + self, + _region: ty::Region<'_>, + ) -> Result { + Ok(self) + } + + fn print_type( + self, + ty: Ty<'tcx>, + ) -> Result { + match ty.sty { + // Print all nominal types 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) + } + _ => self.pretty_print_type(ty), + } + } + + fn print_dyn_existential( + mut self, + predicates: &'tcx ty::List>, + ) -> Result { + let mut first = true; + for p in predicates { + if !first { + write!(self, "+")?; + } + first = false; + self = p.print(self)?; + } + Ok(self) + } + + fn print_const( + mut self, + ct: &'tcx ty::Const<'tcx>, + ) -> Result { + // only print integers + if let ConstValue::Scalar(Scalar::Raw { .. }) = ct.val { + if ct.ty.is_integral() { + return self.pretty_print_const(ct); + } + } + self.write_str("_")?; + Ok(self) + } + + fn path_crate( + mut self, + cnum: CrateNum, + ) -> Result { + self.write_str(&self.tcx.original_crate_name(cnum).as_str())?; + Ok(self) + } + fn path_qualified( + self, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + // Similar to `pretty_path_qualified`, but for the other + // types that are printed as paths (see `print_type` above). + match self_ty.sty { + ty::FnDef(..) | + ty::Opaque(..) | + ty::Projection(_) | + ty::UnnormalizedProjection(_) | + ty::Closure(..) | + ty::Generator(..) + if trait_ref.is_none() => + { + self.print_type(self_ty) + } + + _ => self.pretty_path_qualified(self_ty, trait_ref) + } + } + + fn path_append_impl( + self, + print_prefix: impl FnOnce(Self) -> Result, + _disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.pretty_path_append_impl( + |mut cx| { + cx = print_prefix(cx)?; + + if cx.keep_within_component { + // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it. + cx.write_str("::")?; + } else { + cx.path.finalize_pending_component(); + } + + Ok(cx) + }, + self_ty, + trait_ref, + ) + } + fn path_append( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + self = print_prefix(self)?; + + // Skip `::{{constructor}}` on tuple/unit structs. + match disambiguated_data.data { + DefPathData::Ctor => return Ok(self), + _ => {} + } + + if self.keep_within_component { + // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it. + self.write_str("::")?; + } else { + self.path.finalize_pending_component(); + } + + self.write_str(&disambiguated_data.data.as_interned_str().as_str())?; + Ok(self) + } + fn path_generic_args( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + args: &[Kind<'tcx>], + ) -> Result { + self = print_prefix(self)?; + + let args = args.iter().cloned().filter(|arg| { + match arg.unpack() { + UnpackedKind::Lifetime(_) => false, + _ => true, + } + }); + + if args.clone().next().is_some() { + self.generic_delimiters(|cx| cx.comma_sep(args)) + } else { + Ok(self) + } + } +} + +impl PrettyPrinter<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { + fn region_should_not_be_omitted( + &self, + _region: ty::Region<'_>, + ) -> bool { + false + } + fn comma_sep( + mut self, + mut elems: impl Iterator, + ) -> Result + where T: Print<'tcx, 'tcx, Self, Output = Self, Error = Self::Error> + { + if let Some(first) = elems.next() { + self = first.print(self)?; + for elem in elems { + self.write_str(",")?; + self = elem.print(self)?; + } + } + Ok(self) + } + + fn generic_delimiters( + mut self, + f: impl FnOnce(Self) -> Result, + ) -> Result { + write!(self, "<")?; + + let kept_within_component = + mem::replace(&mut self.keep_within_component, true); + self = f(self)?; + self.keep_within_component = kept_within_component; + + write!(self, ">")?; + + Ok(self) + } +} + +impl fmt::Write for SymbolPrinter<'_, '_> { + fn write_str(&mut self, s: &str) -> fmt::Result { + // Name sanitation. LLVM will happily accept identifiers with weird names, but + // gas doesn't! + // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ + // NVPTX assembly has more strict naming rules than gas, so additionally, dots + // are replaced with '$' there. + + for c in s.chars() { + if self.path.temp_buf.is_empty() { + match c { + 'a'..='z' | 'A'..='Z' | '_' => {} + _ => { + // Underscore-qualify anything that didn't start as an ident. + self.path.temp_buf.push('_'); + } + } + } + match c { + // Escape these with $ sequences + '@' => self.path.temp_buf.push_str("$SP$"), + '*' => self.path.temp_buf.push_str("$BP$"), + '&' => self.path.temp_buf.push_str("$RF$"), + '<' => self.path.temp_buf.push_str("$LT$"), + '>' => self.path.temp_buf.push_str("$GT$"), + '(' => self.path.temp_buf.push_str("$LP$"), + ')' => self.path.temp_buf.push_str("$RP$"), + ',' => self.path.temp_buf.push_str("$C$"), + + '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => { + // NVPTX doesn't support these characters in symbol names. + self.path.temp_buf.push('$') + } + + // '.' doesn't occur in types and functions, so reuse it + // for ':' and '-' + '-' | ':' => self.path.temp_buf.push('.'), + + // Avoid crashing LLVM in certain (LTO-related) situations, see #60925. + 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$6d$"), + + // These are legal symbols + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c), + + _ => { + self.path.temp_buf.push('$'); + for c in c.escape_unicode().skip(1) { + match c { + '{' => {} + '}' => self.path.temp_buf.push('$'), + c => self.path.temp_buf.push(c), + } + } + } + } + } + + Ok(()) + } +} diff --git a/src/librustc_codegen_utils/symbol_names/v0.rs b/src/librustc_codegen_utils/symbol_names/v0.rs new file mode 100644 index 0000000000000..6d37d4cafc350 --- /dev/null +++ b/src/librustc_codegen_utils/symbol_names/v0.rs @@ -0,0 +1,664 @@ +use rustc::hir; +use rustc::hir::def_id::{CrateNum, DefId}; +use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::print::{Printer, Print}; +use rustc::ty::subst::{Kind, Subst, UnpackedKind}; +use rustc_data_structures::base_n; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_mir::monomorphize::Instance; +use rustc_target::spec::abi::Abi; +use syntax::ast::{IntTy, UintTy, FloatTy}; + +use std::fmt::Write; +use std::ops::Range; + +pub(super) fn mangle( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + instance: Instance<'tcx>, + instantiating_crate: Option, + compress: bool, +) -> String { + 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); + + let prefix = "_R"; + let mut cx = SymbolMangler { + tcx, + compress: if compress { + Some(Box::new(CompressionCaches { + start_offset: prefix.len(), + + paths: FxHashMap::default(), + types: FxHashMap::default(), + consts: FxHashMap::default(), + })) + } else { + None + }, + binders: vec![], + out: String::from(prefix), + }; + cx = if instance.is_vtable_shim() { + cx.path_append_ns( + |cx| cx.print_def_path(def_id, substs), + 'S', + 0, + "", + ).unwrap() + } else { + cx.print_def_path(def_id, substs).unwrap() + }; + if let Some(instantiating_crate) = instantiating_crate { + cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap(); + } + cx.out +} + +struct CompressionCaches<'tcx> { + // The length of the prefix in `out` (e.g. 2 for `_R`). + start_offset: usize, + + // The values are start positions in `out`, in bytes. + paths: FxHashMap<(DefId, &'tcx [Kind<'tcx>]), usize>, + types: FxHashMap, usize>, + consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>, +} + +struct BinderLevel { + /// The range of distances from the root of what's + /// being printed, to the lifetimes in a binder. + /// Specifically, a `BrAnon(i)` lifetime has depth + /// `lifetime_depths.start + i`, going away from the + /// the root and towards its use site, as `i` increases. + /// This is used to flatten rustc's pairing of `BrAnon` + /// (intra-binder disambiguation) with a `DebruijnIndex` + /// (binder addressing), to "true" de Bruijn indices, + /// by subtracting the depth of a certain lifetime, from + /// the innermost depth at its use site. + lifetime_depths: Range, +} + +struct SymbolMangler<'a, 'tcx> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + compress: Option>>, + binders: Vec, + out: String, +} + +impl SymbolMangler<'_, 'tcx> { + fn push(&mut self, s: &str) { + self.out.push_str(s); + } + + /// Push a `_`-terminated base 62 integer, using the format + /// specified in the RFC as ``, that is: + /// * `x = 0` is encoded as just the `"_"` terminator + /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, + /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. + fn push_integer_62(&mut self, x: u64) { + if let Some(x) = x.checked_sub(1) { + base_n::push_str(x as u128, 62, &mut self.out); + } + self.push("_"); + } + + /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is: + /// * `x = 0` is encoded as `""` (nothing) + /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)` + /// e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc. + fn push_opt_integer_62(&mut self, tag: &str, x: u64) { + if let Some(x) = x.checked_sub(1) { + self.push(tag); + self.push_integer_62(x); + } + } + + fn push_disambiguator(&mut self, dis: u64) { + self.push_opt_integer_62("s", dis); + } + + fn push_ident(&mut self, ident: &str) { + let mut use_punycode = false; + for b in ident.bytes() { + match b { + b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} + 0x80..=0xff => use_punycode = true, + _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), + } + } + + let punycode_string; + let ident = if use_punycode { + self.push("u"); + + // FIXME(eddyb) we should probably roll our own punycode implementation. + let mut punycode_bytes = match ::punycode::encode(ident) { + Ok(s) => s.into_bytes(), + Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), + }; + + // Replace `-` with `_`. + if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { + *c = b'_'; + } + + // FIXME(eddyb) avoid rechecking UTF-8 validity. + punycode_string = String::from_utf8(punycode_bytes).unwrap(); + &punycode_string + } else { + ident + }; + + let _ = write!(self.out, "{}", ident.len()); + + // Write a separating `_` if necessary (leading digit or `_`). + match ident.chars().next() { + Some('_') | Some('0'..='9') => { + self.push("_"); + } + _ => {} + } + + self.push(ident); + } + + fn path_append_ns( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + ns: char, + disambiguator: u64, + name: &str, + ) -> Result { + self.push("N"); + self.out.push(ns); + self = print_prefix(self)?; + self.push_disambiguator(disambiguator as u64); + self.push_ident(name); + Ok(self) + } + + fn print_backref(mut self, i: usize) -> Result { + self.push("B"); + self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64); + Ok(self) + } + + fn in_binder( + mut self, + value: &ty::Binder, + print_value: impl FnOnce(Self, &T) -> Result + ) -> Result + where T: TypeFoldable<'tcx> + { + let regions = if value.has_late_bound_regions() { + self.tcx.collect_referenced_late_bound_regions(value) + } else { + FxHashSet::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); + + self.push_opt_integer_62("G", lifetimes as u64); + lifetime_depths.end += lifetimes; + + self.binders.push(BinderLevel { lifetime_depths }); + self = print_value(self, value.skip_binder())?; + self.binders.pop(); + + Ok(self) + } +} + +impl Printer<'tcx, 'tcx> for SymbolMangler<'_, 'tcx> { + type Error = !; + + type Path = Self; + type Region = Self; + type Type = Self; + type DynExistential = Self; + type Const = Self; + + fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + fn print_def_path( + mut self, + def_id: DefId, + substs: &'tcx [Kind<'tcx>], + ) -> Result { + if let Some(&i) = self.compress.as_ref().and_then(|c| c.paths.get(&(def_id, substs))) { + return self.print_backref(i); + } + let start = self.out.len(); + + self = self.default_print_def_path(def_id, substs)?; + + // Only cache paths that do not refer to an enclosing + // binder (which would change depending on context). + if !substs.iter().any(|k| k.has_escaping_bound_vars()) { + if let Some(c) = &mut self.compress { + c.paths.insert((def_id, substs), start); + } + } + Ok(self) + } + + fn print_impl_path( + self, + impl_def_id: DefId, + substs: &'tcx [Kind<'tcx>], + mut self_ty: Ty<'tcx>, + mut impl_trait_ref: Option>, + ) -> Result { + let key = self.tcx.def_key(impl_def_id); + let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; + + 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_append_impl( + |cx| cx.print_def_path(parent_def_id, &[]), + &key.disambiguated_data, + self_ty, + impl_trait_ref, + ) + } + + fn print_region( + mut self, + region: ty::Region<'_>, + ) -> Result { + let i = match *region { + // Erased lifetimes use the index 0, for a + // shorter mangling of `L_`. + ty::ReErased => 0, + + // Late-bound lifetimes use indices starting at 1, + // see `BinderLevel` for more details. + ty::ReLateBound(debruijn, ty::BrAnon(i)) => { + let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; + let depth = binder.lifetime_depths.start + i; + + 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth) + } + + _ => bug!("symbol_names: non-erased region `{:?}`", region), + }; + self.push("L"); + self.push_integer_62(i as u64); + Ok(self) + } + + fn print_type( + mut self, + ty: Ty<'tcx>, + ) -> Result { + // Basic types, never cached (single-character). + let basic_type = match ty.sty { + ty::Bool => "b", + ty::Char => "c", + ty::Str => "e", + ty::Tuple(_) if ty.is_unit() => "u", + ty::Int(IntTy::I8) => "a", + ty::Int(IntTy::I16) => "s", + ty::Int(IntTy::I32) => "l", + ty::Int(IntTy::I64) => "x", + ty::Int(IntTy::I128) => "n", + ty::Int(IntTy::Isize) => "i", + ty::Uint(UintTy::U8) => "h", + ty::Uint(UintTy::U16) => "t", + ty::Uint(UintTy::U32) => "m", + ty::Uint(UintTy::U64) => "y", + ty::Uint(UintTy::U128) => "o", + ty::Uint(UintTy::Usize) => "j", + ty::Float(FloatTy::F32) => "f", + ty::Float(FloatTy::F64) => "d", + ty::Never => "z", + + // Placeholders (should be demangled as `_`). + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | + ty::Infer(_) | ty::Error => "p", + + _ => "", + }; + if !basic_type.is_empty() { + self.push(basic_type); + return Ok(self); + } + + if let Some(&i) = self.compress.as_ref().and_then(|c| c.types.get(&ty)) { + return self.print_backref(i); + } + let start = self.out.len(); + + match ty.sty { + // Basic types, handled above. + ty::Bool | ty::Char | ty::Str | + ty::Int(_) | ty::Uint(_) | ty::Float(_) | + ty::Never => unreachable!(), + ty::Tuple(_) if ty.is_unit() => unreachable!(), + + // Placeholders, also handled as part of basic types. + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | + ty::Infer(_) | ty::Error => unreachable!(), + + ty::Ref(r, ty, mutbl) => { + self.push(match mutbl { + hir::MutImmutable => "R", + hir::MutMutable => "Q", + }); + if *r != ty::ReErased { + self = r.print(self)?; + } + self = ty.print(self)?; + } + + ty::RawPtr(mt) => { + self.push(match mt.mutbl { + hir::MutImmutable => "P", + hir::MutMutable => "O", + }); + self = mt.ty.print(self)?; + } + + ty::Array(ty, len) => { + self.push("A"); + self = ty.print(self)?; + self = self.print_const(len)?; + } + ty::Slice(ty) => { + self.push("S"); + self = ty.print(self)?; + } + + ty::Tuple(tys) => { + self.push("T"); + for ty in tys.iter().map(|k| k.expect_ty()) { + self = ty.print(self)?; + } + self.push("E"); + } + + // 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 }, _) => { + self = self.print_def_path(def_id, substs)?; + } + ty::Foreign(def_id) => { + self = self.print_def_path(def_id, &[])?; + } + + ty::FnPtr(sig) => { + self.push("F"); + self = self.in_binder(&sig, |mut cx, sig| { + if sig.unsafety == hir::Unsafety::Unsafe { + cx.push("U"); + } + match sig.abi { + Abi::Rust => {} + Abi::C => cx.push("KC"), + abi => { + cx.push("K"); + let name = abi.name(); + if name.contains('-') { + cx.push_ident(&name.replace('-', "_")); + } else { + cx.push_ident(name); + } + } + } + for &ty in sig.inputs() { + cx = ty.print(cx)?; + } + if sig.c_variadic { + cx.push("v"); + } + cx.push("E"); + sig.output().print(cx) + })?; + } + + ty::Dynamic(predicates, r) => { + self.push("D"); + self = self.in_binder(&predicates, |cx, predicates| { + cx.print_dyn_existential(predicates) + })?; + self = r.print(self)?; + } + + ty::GeneratorWitness(_) => { + bug!("symbol_names: unexpected `GeneratorWitness`") + } + } + + // Only cache types that do not refer to an enclosing + // binder (which would change depending on context). + if !ty.has_escaping_bound_vars() { + if let Some(c) = &mut self.compress { + c.types.insert(ty, start); + } + } + Ok(self) + } + + fn print_dyn_existential( + mut self, + predicates: &'tcx ty::List>, + ) -> Result { + for predicate in predicates { + match *predicate { + ty::ExistentialPredicate::Trait(trait_ref) => { + // Use a type that can't appear in defaults of type parameters. + let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0)); + let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); + self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + ty::ExistentialPredicate::Projection(projection) => { + let name = self.tcx.associated_item(projection.item_def_id).ident; + self.push("p"); + self.push_ident(&name.as_str()); + self = projection.ty.print(self)?; + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + self = self.print_def_path(def_id, &[])?; + } + } + } + self.push("E"); + Ok(self) + } + + fn print_const( + mut self, + ct: &'tcx ty::Const<'tcx>, + ) -> Result { + 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(); + + match ct.ty.sty { + ty::Uint(_) => {} + _ => { + bug!("symbol_names: unsupported constant of type `{}` ({:?})", + ct.ty, ct); + } + } + self = ct.ty.print(self)?; + + if let Some(bits) = ct.assert_bits(self.tcx, ty::ParamEnv::empty().and(ct.ty)) { + let _ = write!(self.out, "{:x}_", 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 + // binder (which would change depending on context). + if !ct.has_escaping_bound_vars() { + if let Some(c) = &mut self.compress { + c.consts.insert(ct, start); + } + } + Ok(self) + } + + fn path_crate( + mut self, + cnum: CrateNum, + ) -> Result { + self.push("C"); + let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint(); + self.push_disambiguator(fingerprint.to_smaller_hash()); + let name = self.tcx.original_crate_name(cnum).as_str(); + self.push_ident(&name); + Ok(self) + } + fn path_qualified( + mut self, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + assert!(trait_ref.is_some()); + let trait_ref = trait_ref.unwrap(); + + self.push("Y"); + self = self_ty.print(self)?; + self.print_def_path(trait_ref.def_id, trait_ref.substs) + } + + fn path_append_impl( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.push(match trait_ref { + Some(_) => "X", + None => "M", + }); + self.push_disambiguator(disambiguated_data.disambiguator as u64); + self = print_prefix(self)?; + self = self_ty.print(self)?; + if let Some(trait_ref) = trait_ref { + self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + Ok(self) + } + fn path_append( + self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + let ns = match disambiguated_data.data { + // Avoid putting the burden on demanglers to ignore this. + DefPathData::Ctor => return print_prefix(self), + + // Uppercase categories are more stable than lowercase ones. + DefPathData::TypeNs(_) => 't', + DefPathData::ValueNs(_) => 'v', + DefPathData::ClosureExpr => 'C', + DefPathData::AnonConst => 'k', + DefPathData::ImplTrait => 'i', + + // These should never show up as `path_append` arguments. + DefPathData::CrateRoot + | DefPathData::Misc + | DefPathData::Impl + | DefPathData::MacroNs(_) + | DefPathData::LifetimeNs(_) + | DefPathData::GlobalMetaData(_) => { + bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) + } + }; + + let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str()); + + self.path_append_ns( + print_prefix, + ns, + disambiguated_data.disambiguator as u64, + name.as_ref().map_or("", |s| &s[..]) + ) + } + fn path_generic_args( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + args: &[Kind<'tcx>], + ) -> Result { + // 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_none() { + return print_prefix(self); + } + + self.push("I"); + self = print_prefix(self)?; + for arg in args { + match arg.unpack() { + UnpackedKind::Lifetime(lt) => { + self = lt.print(self)?; + } + UnpackedKind::Type(ty) => { + self = ty.print(self)?; + } + UnpackedKind::Const(c) => { + self.push("K"); + // FIXME(const_generics) implement `ty::print::Print` on `ty::Const`. + // self = c.print(self)?; + self = self.print_const(c)?; + } + } + } + self.push("E"); + + Ok(self) + } +} diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cc79f7b077eb2..e04372ea280b5 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -176,6 +176,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, r.map(|c| &*tcx.arena.alloc(c)) } is_no_builtins => { cdata.root.no_builtins } + symbol_mangling_version => { cdata.root.symbol_mangling_version } impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } reachable_non_generics => { let reachable_non_generics = tcx diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 588682a2420a9..586fc507dd3eb 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -498,6 +498,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { panic_runtime: attr::contains_name(&attrs, sym::panic_runtime), profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime), sanitizer_runtime: attr::contains_name(&attrs, sym::sanitizer_runtime), + symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version, crate_deps, dylib_dependency_formats, diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 2c3291a41d32b..8d1de4fd6c392 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -8,6 +8,7 @@ use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary, ForeignMo use rustc::middle::lang_items; use rustc::mir; use rustc::session::CrateDisambiguator; +use rustc::session::config::SymbolManglingVersion; use rustc::ty::{self, Ty, ReprOptions}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use rustc_data_structures::svh::Svh; @@ -189,6 +190,7 @@ pub struct CrateRoot<'tcx> { pub panic_runtime: bool, pub profiler_runtime: bool, pub sanitizer_runtime: bool, + pub symbol_mangling_version: SymbolManglingVersion, } #[derive(RustcEncodable, RustcDecodable)] From 408bf9de3459ffbf3b5f8844895d4f0147faad9a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 4 Feb 2019 09:03:31 +0200 Subject: [PATCH 04/10] rustc_codegen_utils: don't ignore `Ctor` path components in symbols. --- src/librustc_codegen_utils/symbol_names/v0.rs | 4 +--- src/test/run-pass/struct-ctor-mangling.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/struct-ctor-mangling.rs diff --git a/src/librustc_codegen_utils/symbol_names/v0.rs b/src/librustc_codegen_utils/symbol_names/v0.rs index 6d37d4cafc350..dc985c8126c54 100644 --- a/src/librustc_codegen_utils/symbol_names/v0.rs +++ b/src/librustc_codegen_utils/symbol_names/v0.rs @@ -586,13 +586,11 @@ impl Printer<'tcx, 'tcx> for SymbolMangler<'_, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result { let ns = match disambiguated_data.data { - // Avoid putting the burden on demanglers to ignore this. - DefPathData::Ctor => return print_prefix(self), - // Uppercase categories are more stable than lowercase ones. DefPathData::TypeNs(_) => 't', DefPathData::ValueNs(_) => 'v', DefPathData::ClosureExpr => 'C', + DefPathData::Ctor => 'c', DefPathData::AnonConst => 'k', DefPathData::ImplTrait => 'i', diff --git a/src/test/run-pass/struct-ctor-mangling.rs b/src/test/run-pass/struct-ctor-mangling.rs new file mode 100644 index 0000000000000..5f5ee7cfe4410 --- /dev/null +++ b/src/test/run-pass/struct-ctor-mangling.rs @@ -0,0 +1,12 @@ +fn size_of_val(_: &T) -> usize { + std::mem::size_of::() +} + +struct Foo(i64); + +// Test that the (symbol) mangling of `Foo` (the `struct` type) and that of +// `typeof Foo` (the function type of the `struct` constructor) don't collide. +fn main() { + size_of_val(&Foo(0)); + size_of_val(&Foo); +} From 5fd3e89d70d7a1d6187c7a6ec55896e5e14d43ba Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 13 Apr 2019 19:03:02 +0300 Subject: [PATCH 05/10] test: support both (`legacy` and `v0`) choices of mangling. --- src/test/codegen/drop.rs | 21 ++++---- src/test/codegen/external-no-mangle-fns.rs | 4 +- .../codegen/external-no-mangle-statics.rs | 4 +- src/test/codegen/internalize-closures.rs | 6 ++- src/test/codegen/link-dead-code.rs | 12 +++-- .../local-generics-in-exe-internalized.rs | 4 +- src/test/codegen/target-cpu-on-functions.rs | 4 +- .../stable-symbol-names/Makefile | 7 +-- .../symbol-visibility/Makefile | 21 ++++---- src/test/run-pass/backtrace.rs | 17 ++++++- .../{basic.stderr => basic.legacy.stderr} | 8 +-- src/test/ui/symbol-names/basic.rs | 17 +++++-- src/test/ui/symbol-names/basic.v0.stderr | 26 ++++++++++ .../{impl1.stderr => impl1.legacy.stderr} | 16 +++--- src/test/ui/symbol-names/impl1.rs | 30 ++++++++--- src/test/ui/symbol-names/impl1.v0.stderr | 50 +++++++++++++++++++ .../ui/symbol-names/issue-60925.legacy.stderr | 20 ++++++++ src/test/ui/symbol-names/issue-60925.rs | 16 ++++-- .../ui/symbol-names/issue-60925.v0.stderr | 20 ++++++++ 19 files changed, 245 insertions(+), 58 deletions(-) rename src/test/ui/symbol-names/{basic.stderr => basic.legacy.stderr} (86%) create mode 100644 src/test/ui/symbol-names/basic.v0.stderr rename src/test/ui/symbol-names/{impl1.stderr => impl1.legacy.stderr} (86%) create mode 100644 src/test/ui/symbol-names/impl1.v0.stderr create mode 100644 src/test/ui/symbol-names/issue-60925.legacy.stderr create mode 100644 src/test/ui/symbol-names/issue-60925.v0.stderr diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs index 7e6f8eaaa30d2..307c4e2c1e273 100644 --- a/src/test/codegen/drop.rs +++ b/src/test/codegen/drop.rs @@ -19,15 +19,18 @@ pub fn droppy() { // that's one new drop call per call to possibly_unwinding(), and finally 3 drop calls for the // regular function exit. We used to have problems with quadratic growths of drop calls in such // functions. -// CHECK-NOT: invoke{{.*}}drop{{.*}}SomeUniqueName -// CHECK: call{{.*}}drop{{.*}}SomeUniqueName -// CHECK: call{{.*}}drop{{.*}}SomeUniqueName -// CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName -// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName -// CHECK: call{{.*}}drop{{.*}}SomeUniqueName -// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName -// CHECK: call{{.*}}drop{{.*}}SomeUniqueName -// CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName +// FIXME(eddyb) the `void @` forces a match on the instruction, instead of the +// comment, that's `; call core::ptr::real_drop_in_place::` +// for the `v0` mangling, should switch to matching on that once `legacy` is gone. +// CHECK-NOT: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName +// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName +// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName +// CHECK-NOT: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName +// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName +// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName +// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName +// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName +// CHECK-NOT: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName // The next line checks for the } that ends the function definition // CHECK-LABEL: {{^[}]}} let _s = SomeUniqueName; diff --git a/src/test/codegen/external-no-mangle-fns.rs b/src/test/codegen/external-no-mangle-fns.rs index 79d5dc2400c40..902882144996f 100644 --- a/src/test/codegen/external-no-mangle-fns.rs +++ b/src/test/codegen/external-no-mangle-fns.rs @@ -33,7 +33,9 @@ const HIDDEN: () = { }; // The surrounding item should not accidentally become external -// CHECK: define internal{{.*}} void @_ZN22external_no_mangle_fns1x +// CHECK-LABEL: ; external_no_mangle_fns::x +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal #[inline(never)] fn x() { // CHECK: define void @g() diff --git a/src/test/codegen/external-no-mangle-statics.rs b/src/test/codegen/external-no-mangle-statics.rs index 2998000180edb..e44373926b76a 100644 --- a/src/test/codegen/external-no-mangle-statics.rs +++ b/src/test/codegen/external-no-mangle-statics.rs @@ -75,4 +75,6 @@ fn x() { #[no_mangle] pub static mut P: u8 = 0; } -// CHECK: define internal void @_ZN26external_no_mangle_statics1x{{.*$}} +// CHECK-LABEL: ; external_no_mangle_statics::x +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal diff --git a/src/test/codegen/internalize-closures.rs b/src/test/codegen/internalize-closures.rs index 3434820aa8a18..8d9192c6fa0c1 100644 --- a/src/test/codegen/internalize-closures.rs +++ b/src/test/codegen/internalize-closures.rs @@ -4,7 +4,11 @@ pub fn main() { // We want to make sure that closures get 'internal' linkage instead of // 'weak_odr' when they are not shared between codegen units - // CHECK: define internal {{.*}}_ZN20internalize_closures4main{{.*}}$u7b$$u7b$closure$u7d$$u7d$ + // FIXME(eddyb) `legacy` mangling uses `{{closure}}`, while `v0` + // uses `{closure#0}`, switch to the latter once `legacy` is gone. + // CHECK-LABEL: ; internalize_closures::main::{{.*}}closure + // CHECK-NEXT: ; Function Attrs: + // CHECK-NEXT: define internal let c = |x:i32| { x + 1 }; let _ = c(1); } diff --git a/src/test/codegen/link-dead-code.rs b/src/test/codegen/link-dead-code.rs index cb3dd07a2a798..de5a237c5f8a3 100644 --- a/src/test/codegen/link-dead-code.rs +++ b/src/test/codegen/link-dead-code.rs @@ -5,12 +5,18 @@ // This test makes sure that, when -Clink-dead-code is specified, we generate // code for functions that would otherwise be skipped. -// CHECK-LABEL: define hidden i32 @_ZN14link_dead_code8const_fn +// CHECK-LABEL: ; link_dead_code::const_fn +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define hidden const fn const_fn() -> i32 { 1 } -// CHECK-LABEL: define hidden i32 @_ZN14link_dead_code9inline_fn +// CHECK-LABEL: ; link_dead_code::inline_fn +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define hidden #[inline] fn inline_fn() -> i32 { 2 } -// CHECK-LABEL: define hidden i32 @_ZN14link_dead_code10private_fn +// CHECK-LABEL: ; link_dead_code::private_fn +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define hidden fn private_fn() -> i32 { 3 } diff --git a/src/test/codegen/local-generics-in-exe-internalized.rs b/src/test/codegen/local-generics-in-exe-internalized.rs index 6bdbf92919389..e5430fbf17a1d 100644 --- a/src/test/codegen/local-generics-in-exe-internalized.rs +++ b/src/test/codegen/local-generics-in-exe-internalized.rs @@ -2,7 +2,9 @@ // Check that local generics are internalized if they are in the same CGU -// CHECK: define internal {{.*}} @_ZN34local_generics_in_exe_internalized3foo{{.*}} +// CHECK-LABEL: ; local_generics_in_exe_internalized::foo +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal pub fn foo(x: T, y: T) -> (T, T) { (x, y) } diff --git a/src/test/codegen/target-cpu-on-functions.rs b/src/test/codegen/target-cpu-on-functions.rs index 3fdf6ab6d002f..523216deb8400 100644 --- a/src/test/codegen/target-cpu-on-functions.rs +++ b/src/test/codegen/target-cpu-on-functions.rs @@ -13,7 +13,9 @@ pub extern fn exported() { not_exported(); } -// CHECK-LABEL: define {{.*}} @_ZN23target_cpu_on_functions12not_exported{{.*}}() {{.*}} #0 +// CHECK-LABEL: ; target_cpu_on_functions::not_exported +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define {{.*}}() {{.*}} #0 fn not_exported() {} // CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}" diff --git a/src/test/run-make-fulldeps/stable-symbol-names/Makefile b/src/test/run-make-fulldeps/stable-symbol-names/Makefile index 3cbc5593ac0a2..451af809b2223 100644 --- a/src/test/run-make-fulldeps/stable-symbol-names/Makefile +++ b/src/test/run-make-fulldeps/stable-symbol-names/Makefile @@ -3,14 +3,15 @@ # The following command will: # 1. dump the symbols of a library using `nm` # 2. extract only those lines that we are interested in via `grep` -# 3. from those lines, extract just the symbol name via `sed` -# (symbol names always start with "_ZN" and end with "E") +# 3. from those lines, extract just the symbol name via `sed`, which: +# * always starts with "_ZN" and ends with "E" (`legacy` mangling) +# * always starts with "_R" (`v0` mangling) # 4. sort those symbol names for deterministic comparison # 5. write the result into a file dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \ | grep -E "$(2)" \ - | sed "s/.*\(_ZN.*E\).*/\1/" \ + | sed -E "s/.*(_ZN.*E|_R[a-zA-Z0-9_]*).*/\1/" \ | sort \ > "$(TMPDIR)/$(1)$(3).nm" diff --git a/src/test/run-make-fulldeps/symbol-visibility/Makefile b/src/test/run-make-fulldeps/symbol-visibility/Makefile index d99470e30d7ee..7901866015bf2 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/Makefile +++ b/src/test/run-make-fulldeps/symbol-visibility/Makefile @@ -19,6 +19,9 @@ EXE_NAME=an_executable COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dylib endif +# `grep` regex for symbols produced by either `legacy` or `v0` mangling +RE_ANY_RUST_SYMBOL="_ZN.*h.*E\|_R[a-zA-Z0-9_]+" + all: $(RUSTC) -Zshare-generics=no an_rlib.rs $(RUSTC) -Zshare-generics=no a_cdylib.rs @@ -31,20 +34,20 @@ all: # Check that a cdylib exports the public #[no_mangle] functions of dependencies [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions - [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ] # Check that a Rust dylib exports its monomorphic functions [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ] # Check that a Rust dylib does not export generics if -Zshare-generics=no - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "0" ] # Check that a Rust dylib exports the monomorphic functions from its dependencies [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] # Check that a Rust dylib does not export generics if -Zshare-generics=no - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "0" ] # Check that an executable does not export any dynamic symbols [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] @@ -58,7 +61,7 @@ all: # Check that a cdylib exports the public #[no_mangle] functions of dependencies [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions - [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ] $(RUSTC) -Zshare-generics=yes an_rlib.rs @@ -71,17 +74,17 @@ all: # Check that a cdylib exports the public #[no_mangle] functions of dependencies [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions - [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ] # Check that a Rust dylib exports its monomorphic functions, including generics this time [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "1" ] # Check that a Rust dylib exports the monomorphic functions from its dependencies [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "1" ] # Check that an executable does not export any dynamic symbols [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 5f6198aff5009..c73ba293ee25b 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -42,6 +42,21 @@ fn expected(fn_name: &str) -> String { format!(" backtrace::{}", fn_name) } +fn contains_verbose_expected(s: &str, fn_name: &str) -> bool { + // HACK(eddyb) work around the fact that verbosely demangled stack traces + // (from `RUST_BACKTRACE=full`, or, as is the case here, panic-in-panic) + // may contain symbols with hashes in them, i.e. `backtrace[...]::`. + let prefix = " backtrace"; + let suffix = &format!("::{}", fn_name); + s.match_indices(prefix).any(|(i, _)| { + s[i + prefix.len()..] + .trim_start_matches('[') + .trim_start_matches(char::is_alphanumeric) + .trim_start_matches(']') + .starts_with(suffix) + }) +} + fn runtest(me: &str) { // Make sure that the stack trace is printed let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap(); @@ -79,7 +94,7 @@ fn runtest(me: &str) { let s = str::from_utf8(&out.stderr).unwrap(); // loosened the following from double::h to double:: due to // spurious failures on mac, 32bit, optimized - assert!(s.contains("stack backtrace") && s.contains(&expected("double")), + assert!(s.contains("stack backtrace") && contains_verbose_expected(s, "double"), "bad output3: {}", s); // Make sure a stack trace isn't printed too many times diff --git a/src/test/ui/symbol-names/basic.stderr b/src/test/ui/symbol-names/basic.legacy.stderr similarity index 86% rename from src/test/ui/symbol-names/basic.stderr rename to src/test/ui/symbol-names/basic.legacy.stderr index ebb8b4390d28d..e26168dcfc488 100644 --- a/src/test/ui/symbol-names/basic.stderr +++ b/src/test/ui/symbol-names/basic.legacy.stderr @@ -1,23 +1,23 @@ error: symbol-name(_ZN5basic4main17hd72940ef9669d526E) - --> $DIR/basic.rs:3:1 + --> $DIR/basic.rs:7:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling(basic::main::hd72940ef9669d526) - --> $DIR/basic.rs:3:1 + --> $DIR/basic.rs:7:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(basic::main) - --> $DIR/basic.rs:3:1 + --> $DIR/basic.rs:7:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: def-path(main) - --> $DIR/basic.rs:7:1 + --> $DIR/basic.rs:14:1 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/symbol-names/basic.rs b/src/test/ui/symbol-names/basic.rs index 1459ac014ea35..aa88184eddfd4 100644 --- a/src/test/ui/symbol-names/basic.rs +++ b/src/test/ui/symbol-names/basic.rs @@ -1,9 +1,18 @@ +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy + //[v0]compile-flags: -Z symbol-mangling-version=v0 + #![feature(rustc_attrs)] #[rustc_symbol_name] -//~^ ERROR symbol-name(_ZN5basic4main -//~| ERROR demangling(basic::main -//~| ERROR demangling-alt(basic::main) -#[rustc_def_path] //~ ERROR def-path(main) +//[legacy]~^ ERROR symbol-name(_ZN5basic4main +//[legacy]~| ERROR demangling(basic::main +//[legacy]~| ERROR demangling-alt(basic::main) + //[v0]~^^^^ ERROR symbol-name(_RNvCs4fqI2P2rA04_5basic4main) + //[v0]~| ERROR demangling(basic[317d481089b8c8fe]::main) + //[v0]~| ERROR demangling-alt(basic::main) +#[rustc_def_path] +//[legacy]~^ ERROR def-path(main) + //[v0]~^^ ERROR def-path(main) fn main() { } diff --git a/src/test/ui/symbol-names/basic.v0.stderr b/src/test/ui/symbol-names/basic.v0.stderr new file mode 100644 index 0000000000000..40a39daaedce1 --- /dev/null +++ b/src/test/ui/symbol-names/basic.v0.stderr @@ -0,0 +1,26 @@ +error: symbol-name(_RNvCs4fqI2P2rA04_5basic4main) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(basic[317d481089b8c8fe]::main) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(basic::main) + --> $DIR/basic.rs:7:1 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(main) + --> $DIR/basic.rs:14:1 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/symbol-names/impl1.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr similarity index 86% rename from src/test/ui/symbol-names/impl1.stderr rename to src/test/ui/symbol-names/impl1.legacy.stderr index 3a7d540c4882d..298841aa7c974 100644 --- a/src/test/ui/symbol-names/impl1.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -1,47 +1,47 @@ error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE) - --> $DIR/impl1.rs:8:9 + --> $DIR/impl1.rs:12:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling(impl1::foo::Foo::bar::he53b9bee7600ed8d) - --> $DIR/impl1.rs:8:9 + --> $DIR/impl1.rs:12:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(impl1::foo::Foo::bar) - --> $DIR/impl1.rs:8:9 + --> $DIR/impl1.rs:12:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: def-path(foo::Foo::bar) - --> $DIR/impl1.rs:12:9 + --> $DIR/impl1.rs:19:9 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E) - --> $DIR/impl1.rs:21:9 + --> $DIR/impl1.rs:30:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling(impl1::bar::::baz::h86c41f0462d901d4) - --> $DIR/impl1.rs:21:9 + --> $DIR/impl1.rs:30:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(impl1::bar::::baz) - --> $DIR/impl1.rs:21:9 + --> $DIR/impl1.rs:30:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: def-path(bar::::baz) - --> $DIR/impl1.rs:25:9 + --> $DIR/impl1.rs:37:9 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 803fa856b60cf..2b30362e41977 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -1,3 +1,7 @@ +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy + //[v0]compile-flags: -Z symbol-mangling-version=v0 + #![feature(rustc_attrs)] #![allow(dead_code)] @@ -6,10 +10,15 @@ mod foo { impl Foo { #[rustc_symbol_name] - //~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar - //~| ERROR demangling(impl1::foo::Foo::bar - //~| ERROR demangling-alt(impl1::foo::Foo::bar) - #[rustc_def_path] //~ ERROR def-path(foo::Foo::bar) + //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar + //[legacy]~| ERROR demangling(impl1::foo::Foo::bar + //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar) + //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar) + //[v0]~| ERROR demangling(::bar) + //[v0]~| ERROR demangling-alt(::bar) + #[rustc_def_path] + //[legacy]~^ ERROR def-path(foo::Foo::bar) + //[v0]~^^ ERROR def-path(foo::Foo::bar) fn bar() { } } } @@ -19,10 +28,15 @@ mod bar { impl Foo { #[rustc_symbol_name] - //~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz - //~| ERROR demangling(impl1::bar::::baz - //~| ERROR demangling-alt(impl1::bar::::baz) - #[rustc_def_path] //~ ERROR def-path(bar::::baz) + //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz + //[legacy]~| ERROR demangling(impl1::bar::::baz + //[legacy]~| ERROR demangling-alt(impl1::bar::::baz) + //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz) + //[v0]~| ERROR demangling(::baz) + //[v0]~| ERROR demangling-alt(::baz) + #[rustc_def_path] + //[legacy]~^ ERROR def-path(bar::::baz) + //[v0]~^^ ERROR def-path(bar::::baz) fn baz() { } } } diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr new file mode 100644 index 0000000000000..9f6314a6c29f0 --- /dev/null +++ b/src/test/ui/symbol-names/impl1.v0.stderr @@ -0,0 +1,50 @@ +error: symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar) + --> $DIR/impl1.rs:12:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(::bar) + --> $DIR/impl1.rs:12:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(::bar) + --> $DIR/impl1.rs:12:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(foo::Foo::bar) + --> $DIR/impl1.rs:19:9 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz) + --> $DIR/impl1.rs:30:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(::baz) + --> $DIR/impl1.rs:30:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(::baz) + --> $DIR/impl1.rs:30:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(bar::::baz) + --> $DIR/impl1.rs:37:9 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr new file mode 100644 index 0000000000000..0bbe424aa025b --- /dev/null +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo17h059a991a004536adE) + --> $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(issue_60925::foo::Foo $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(issue_60925::foo::Foo $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs index 22efa978bd2b6..09d68eebb950e 100644 --- a/src/test/ui/symbol-names/issue-60925.rs +++ b/src/test/ui/symbol-names/issue-60925.rs @@ -1,8 +1,13 @@ +// ignore-tidy-linelength +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy + //[v0]compile-flags: -Z symbol-mangling-version=v0 + #![feature(rustc_attrs)] // This test is the same code as in ui/issue-53912.rs but this test checks that the symbol mangling // fix produces the correct result, whereas that test just checks that the reproduction compiles -// successfully and doesn't segfault +// successfully and doesn't crash LLVM fn dummy() {} @@ -14,9 +19,12 @@ mod foo { impl Foo<::llvm::Foo> { #[rustc_symbol_name] - //~^ ERROR symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo - //~| ERROR demangling(issue_60925::foo::Foo>::foo) + //[v0]~| ERROR demangling-alt(>::foo) pub(crate) fn foo() { for _ in 0..0 { for _ in &[::dummy()] { diff --git a/src/test/ui/symbol-names/issue-60925.v0.stderr b/src/test/ui/symbol-names/issue-60925.v0.stderr new file mode 100644 index 0000000000000..5ead40211d20d --- /dev/null +++ b/src/test/ui/symbol-names/issue-60925.v0.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_RNvMNtCs4fqI2P2rA04_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo) + --> $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(>::foo) + --> $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(>::foo) + --> $DIR/issue-60925.rs:21:9 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From e3315075f92700eefe2178ab8c02533295497f74 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 30 Jan 2019 00:53:36 +0200 Subject: [PATCH 06/10] test: force `legacy` mangling for run-make-fulldeps/a-b-a-linker-guard. --- src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile b/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile index 0962ebfbff546..54526e8ef23b3 100644 --- a/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile +++ b/src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile @@ -4,9 +4,12 @@ # of types, it will not run with a dylib that has a different set of # types. +# NOTE(eddyb) this test only works with the `legacy` mangling, +# and will probably get removed once `legacy` is gone. + all: - $(RUSTC) a.rs --cfg x -C prefer-dynamic - $(RUSTC) b.rs -C prefer-dynamic + $(RUSTC) a.rs --cfg x -C prefer-dynamic -Z symbol-mangling-version=legacy + $(RUSTC) b.rs -C prefer-dynamic -Z symbol-mangling-version=legacy $(call RUN,b) - $(RUSTC) a.rs --cfg y -C prefer-dynamic + $(RUSTC) a.rs --cfg y -C prefer-dynamic -Z symbol-mangling-version=legacy $(call FAIL,b) From 0e5f27b1696148d584deb939a5d172ff4a4fe432 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 30 May 2019 00:42:56 +0300 Subject: [PATCH 07/10] rustc_codegen_utils: add harness for dumping/checking symbol names, and mw mangling impl. --- Cargo.lock | 16 + src/librustc_codegen_utils/Cargo.toml | 4 + src/librustc_codegen_utils/symbol_names.rs | 16 +- .../symbol_names/dump.rs | 558 ++++++++++++++++++ .../symbol_names/legacy.rs | 9 +- src/librustc_codegen_utils/symbol_names/mw.rs | 370 ++++++++++++ src/tools/tidy/src/extdeps.rs | 4 + 7 files changed, 974 insertions(+), 3 deletions(-) create mode 100644 src/librustc_codegen_utils/symbol_names/dump.rs create mode 100644 src/librustc_codegen_utils/symbol_names/mw.rs diff --git a/Cargo.lock b/Cargo.lock index a13bc0e74760a..2573c6c659e86 100644 --- a/Cargo.lock +++ b/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)" = "" "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" diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 268be2b109114..9bcfb4a70458c 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -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" diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 134cbaaa3b398..0b78b94866276 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -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 } diff --git a/src/librustc_codegen_utils/symbol_names/dump.rs b/src/librustc_codegen_utils/symbol_names/dump.rs new file mode 100644 index 0000000000000..0a60d3895e90c --- /dev/null +++ b/src/librustc_codegen_utils/symbol_names/dump.rs @@ -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 = { + std::env::var_os("RUST_SYMBOL_DUMP_DIR").map(PathBuf::from) +}); +thread_local!(static OUTPUT: RefCell> = RefCell::new(None)); + +pub fn record( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + instance: Instance<'tcx>, + instantiating_crate: Option, + 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, +} + +// 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, +} + +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, + ns: char, + disambiguator: u64, + name: &str, + ) -> Result { + 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>, + ) -> Result { + 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 { + 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 { + 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>, + ) -> Result { + // 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 { + 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.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>, + ) -> Result { + 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, + _disambiguated_data: &DisambiguatedDefPathData, + _self_ty: Ty<'tcx>, + _trait_ref: Option>, + ) -> Result { + unreachable!() + } + fn path_append( + self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + 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, + args: &[Kind<'tcx>], + ) -> Result { + 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, + ) -> Result { + 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( + mut self, + value: &ty::Binder, + ) -> Result + 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) + } +} diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs index 53682b9bdc2c8..5393eecb7f451 100644 --- a/src/librustc_codegen_utils/symbol_names/legacy.rs +++ b/src/librustc_codegen_utils/symbol_names/legacy.rs @@ -18,6 +18,7 @@ pub(super) fn mangle( tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>, instantiating_crate: Option, + 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}}"); diff --git a/src/librustc_codegen_utils/symbol_names/mw.rs b/src/librustc_codegen_utils/symbol_names/mw.rs new file mode 100644 index 0000000000000..dbb6a7606e172 --- /dev/null +++ b/src/librustc_codegen_utils/symbol_names/mw.rs @@ -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, +) -> 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; + type Region = !; + type Type = Arc; + 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>, + ) -> Result { + 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 { + bug!("mw::print_region: should never be called") + } + + fn print_type( + self, + ty: Ty<'tcx>, + ) -> Result { + 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::, _>>()?; + 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::, _>>()?; + 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>, + ) -> Result { + Err(Unsupported) + } + + fn print_const( + self, + _ct: &'tcx ty::Const<'tcx>, + ) -> Result { + Err(Unsupported) + } + + fn path_crate( + self, + cnum: CrateNum, + ) -> Result { + 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>, + ) -> Result { + 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, + disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + 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::::..` becomes `< 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, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + 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, + args: &[Kind<'tcx>], + ) -> Result { + 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) + } +} diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index 52e263df5e3d3..2caf41079f042 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -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. From 6386a31c5b940bc5a5a4c49450247454bc002632 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 4 Apr 2019 21:29:07 +0300 Subject: [PATCH 08/10] rustc_codegen_utils: update mw's symbol mangler implementation. --- Cargo.lock | 6 +- src/librustc_codegen_utils/Cargo.toml | 2 +- src/librustc_codegen_utils/symbol_names/mw.rs | 383 ++++++++++-------- src/tools/tidy/src/extdeps.rs | 4 +- 4 files changed, 223 insertions(+), 172 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2573c6c659e86..d16a9a53ddcd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2699,7 +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)", + "std-mangle-rs 0.1.0 (git+https://github.com/michaelwoerister/std-mangle-rs?rev=e884304cfcb2f636db4d59ca8ad8fa95b983281c)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -3339,7 +3339,7 @@ dependencies = [ [[package]] name = "std-mangle-rs" version = "0.1.0" -source = "git+https://github.com/michaelwoerister/std-mangle-rs?rev=2336dcdfcc91db3cdda18eda73aca488773ac6fc#2336dcdfcc91db3cdda18eda73aca488773ac6fc" +source = "git+https://github.com/michaelwoerister/std-mangle-rs?rev=e884304cfcb2f636db4d59ca8ad8fa95b983281c#e884304cfcb2f636db4d59ca8ad8fa95b983281c" dependencies = [ "unic-idna-punycode 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4368,7 +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)" = "" +"checksum std-mangle-rs 0.1.0 (git+https://github.com/michaelwoerister/std-mangle-rs?rev=e884304cfcb2f636db4d59ca8ad8fa95b983281c)" = "" "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" diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 9bcfb4a70458c..4023d79df3a96 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -26,4 +26,4 @@ rustc_mir = { path = "../librustc_mir" } [dependencies.std-mangle-rs] git = "https://github.com/michaelwoerister/std-mangle-rs" -rev = "2336dcdfcc91db3cdda18eda73aca488773ac6fc" +rev = "e884304cfcb2f636db4d59ca8ad8fa95b983281c" diff --git a/src/librustc_codegen_utils/symbol_names/mw.rs b/src/librustc_codegen_utils/symbol_names/mw.rs index dbb6a7606e172..c0d8fe5445bd9 100644 --- a/src/librustc_codegen_utils/symbol_names/mw.rs +++ b/src/librustc_codegen_utils/symbol_names/mw.rs @@ -1,4 +1,4 @@ -use std_mangle_rs::{ast, compress::compress_ext}; +use std_mangle_rs::ast; use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId}; @@ -6,7 +6,6 @@ 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}; @@ -25,25 +24,29 @@ pub(super) fn mangle( } let symbol = ast::Symbol { - name: SymbolPrinter { tcx } + version: None, + path: 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), - }) - }), + instantiating_crate: match instantiating_crate { + Some(instantiating_crate) => Some( + SymbolPrinter { tcx } + .path_crate(instantiating_crate)? + ), + None => None, + }, }; - let mut uncompressed = String::new(); + let _ = symbol; + unimplemented!("missing compressor/mangler for mw symbol mangling"); + + /*let mut uncompressed = String::new(); symbol.mangle(&mut uncompressed); - let (compressed_symbol, _) = compress_ext(&symbol); + let (compressed_symbol, _) = std_mangle_rs::compress::compress_ext(&symbol); let mut compressed = String::new(); compressed_symbol.mangle(&mut compressed); - Ok((uncompressed, compressed)) + Ok((uncompressed, compressed))*/ } #[derive(Copy, Clone)] @@ -54,11 +57,11 @@ struct SymbolPrinter<'a, 'tcx> { impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { type Error = Unsupported; - type Path = Arc; - type Region = !; - type Type = Arc; - type DynExistential = !; - type Const = !; + type Path = ast::Path; + type Region = ast::Lifetime; + type Type = ast::Type; + type DynExistential = ast::DynBounds; + type Const = ast::Const; fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx @@ -84,9 +87,21 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { fn print_region( self, - _region: ty::Region<'_>, + region: ty::Region<'_>, ) -> Result { - bug!("mw::print_region: should never be called") + let i = match *region { + ty::ReErased => 0, + + // FIXME(eddyb) copy the implementation over to here. + ty::ReLateBound(_, ty::BrAnon(_)) => { + return Err(Unsupported); + } + + _ => bug!("mw: non-erased region `{:?}`", region), + }; + Ok(ast::Lifetime { + debruijn_index: ast::Base62Number(i), + }) } fn print_type( @@ -96,7 +111,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { macro_rules! basic { ($name:ident) => (ast::Type::BasicType(ast::BasicType::$name)) } - Ok(Arc::new(match ty.sty { + Ok(match ty.sty { ty::Bool => basic!(Bool), ty::Char => basic!(Char), ty::Str => basic!(Str), @@ -117,21 +132,34 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { 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)?), + // Placeholders (should be demangled as `_`). + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | + ty::Infer(_) | ty::Error => basic!(Placeholder), + + ty::Ref(r, ty, mutbl) => { + let lt = if *r != ty::ReErased { + Some(r.print(self)?) + } else { + None + }; + let ty = Arc::new(ty.print(self)?); + match mutbl { + hir::MutImmutable => ast::Type::Ref(lt, ty), + hir::MutMutable => ast::Type::RefMut(lt, ty), + } + } ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::MutImmutable }) => { - ast::Type::RawPtrConst(ty.print(self)?) + ast::Type::RawPtrConst(Arc::new(ty.print(self)?)) } ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::MutMutable }) => { - ast::Type::RawPtrMut(ty.print(self)?) + ast::Type::RawPtrMut(Arc::new(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)?) + ast::Type::Array(Arc::new(ty.print(self)?), Arc::new(len.print(self)?)) } - ty::Slice(ty) => ast::Type::Array(None, ty.print(self)?), + ty::Slice(ty) => ast::Type::Slice(Arc::new(ty.print(self)?)), ty::Tuple(tys) => { let tys = tys.iter() @@ -148,59 +176,113 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { 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)?) + ast::Type::Named(Arc::new(self.print_def_path(def_id, substs)?)) } ty::Foreign(def_id) => { - ast::Type::Named(self.print_def_path(def_id, &[])?) + ast::Type::Named(Arc::new(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() + let mut param_types = sig.inputs().skip_binder().iter() .map(|ty| ty.print(self)) .collect::, _>>()?; if sig.c_variadic() { - params.push(Arc::new(basic!(Ellipsis))); + param_types.push(basic!(Ellipsis)); } - let output = *sig.output().skip_binder(); - let return_type = if output.is_unit() { - None - } else { - Some(output.print(self)?) - }; - ast::Type::Fn { + let return_type = sig.output().skip_binder().print(self)?; + ast::Type::Fn(Arc::new(ast::FnSig { + binder: ast::Binder { + // FIXME(eddyb) needs to be implemented, see `print_region`. + count: ast::Base62Number(0), + }, is_unsafe: sig.unsafety() == hir::Unsafety::Unsafe, abi: match sig.abi() { - Abi::Rust => ast::Abi::Rust, - Abi::C => ast::Abi::C, - _ => return Err(Unsupported), + Abi::Rust => None, + Abi::C => Some(ast::Abi::C), + abi => Some(ast::Abi::Named(ast::UIdent(abi.name().replace('-', "_")))), }, - params, + param_types, return_type, - } + })) + } + + ty::Dynamic(predicates, r) => { + let bounds = Arc::new(self.print_dyn_existential(predicates.skip_binder())?); + let lt = r.print(self)?; + ast::Type::DynTrait(bounds, lt) } - _ => return Err(Unsupported), - })) + ty::GeneratorWitness(_) => { + bug!("mw: unexpected `GeneratorWitness`") + } + }) } fn print_dyn_existential( self, - _predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>, ) -> Result { - Err(Unsupported) + let mut traits = vec![]; + for predicate in predicates { + match *predicate { + ty::ExistentialPredicate::Trait(trait_ref) => { + // Use a type that can't appear in defaults of type parameters. + let dummy_self = self.tcx.mk_infer(ty::FreshTy(0)); + let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); + traits.push(ast::DynTrait { + path: self.print_def_path(trait_ref.def_id, trait_ref.substs)?, + assoc_type_bindings: vec![], + }); + } + ty::ExistentialPredicate::Projection(projection) => { + let name = self.tcx.associated_item(projection.item_def_id).ident; + traits.last_mut().unwrap().assoc_type_bindings.push(ast::DynTraitAssocBinding { + ident: ast::UIdent(name.to_string()), + ty: projection.ty.print(self)?, + }); + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + traits.push(ast::DynTrait { + path: self.print_def_path(def_id, &[])?, + assoc_type_bindings: vec![], + }); + } + } + } + + Ok(ast::DynBounds { + binder: ast::Binder { + // FIXME(eddyb) needs to be implemented, see `print_region`. + count: ast::Base62Number(0), + }, + traits, + }) } fn print_const( self, - _ct: &'tcx ty::Const<'tcx>, + ct: &'tcx ty::Const<'tcx>, ) -> Result { - Err(Unsupported) + match ct.ty.sty { + ty::Uint(_) => {} + _ => { + bug!("mw: unsupported constant of type `{}` ({:?})", + ct.ty, ct); + } + } + let ty = ct.ty.print(self)?; + + if let Some(bits) = ct.assert_bits(self.tcx, ty::ParamEnv::empty().and(ct.ty)) { + if bits as u64 as u128 != bits { + return Err(Unsupported); + } + Ok(ast::Const::Value(ty, bits as u64)) + } 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. + Ok(ast::Const::Placeholder(ty)) + } } fn path_crate( @@ -208,14 +290,12 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { cnum: CrateNum, ) -> Result { 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(), - })) + Ok(ast::Path::CrateRoot { + id: ast::Ident { + dis: ast::Base62Number(fingerprint.to_smaller_hash()), + u_ident: ast::UIdent(self.tcx.original_crate_name(cnum).to_string()), + }, + }) } fn path_qualified( self, @@ -226,15 +306,10 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { let trait_ref = trait_ref.unwrap(); // This is a default method in the trait declaration. - let path = ast::PathPrefix::TraitImpl { + Ok(ast::Path::TraitDef { 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(), - })) + trait_name: Arc::new(self.print_def_path(trait_ref.def_id, trait_ref.substs)?), + }) } fn path_append_impl( @@ -244,127 +319,103 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result { - 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::::..` becomes `< 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), + let impl_path = ast::ImplPath { + dis: Some(ast::Base62Number(disambiguated_data.disambiguator as u64)), + path: Arc::new(print_prefix(self)?), }; - Ok(Arc::new(ast::AbsolutePath::Path { - name: Arc::new(path), - args: ast::GenericArgumentList::new_empty(), - })) + let self_type = self_ty.print(self)?; + match trait_ref { + Some(trait_ref) => Ok(ast::Path::TraitImpl { + impl_path, + self_type, + trait_name: Arc::new(self.print_def_path(trait_ref.def_id, trait_ref.substs)?), + }), + None => Ok(ast::Path::InherentImpl { + impl_path, + self_type, + }), + } } fn path_append( self, print_prefix: impl FnOnce(Self) -> Result, disambiguated_data: &DisambiguatedDefPathData, ) -> Result { - let mut path = print_prefix(self)?; + let inner = Arc::new(print_prefix(self)?); - let (prefix, ast_args) = match Arc::make_mut(&mut path) { - ast::AbsolutePath::Path { name, args } => (name, args), - _ => unreachable!(), - }; + let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str()); + let name = name.as_ref().map_or("", |s| &s[..]); + let ns = match disambiguated_data.data { + DefPathData::ClosureExpr => ast::Namespace(b'C'), - 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). + // Lowercase a-z are unspecified disambiguation categories. _ => { - 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 + let discriminant = unsafe { + ::std::intrinsics::discriminant_value(&disambiguated_data.data) }; - ident.push(tag); + assert!(discriminant < 26); - ast::IdentTag::TypeNs - } - }; - - let dis = ast::NumericDisambiguator(disambiguated_data.disambiguator as u64); + // Mix in the name to avoid making it too predictable. + let mut d = (discriminant ^ 0x55) % 26; + for (i, b) in name.bytes().enumerate() { + d = (d + i as u64 + b as u64) % 26; + } - let prefix = if !ast_args.is_empty() { - Arc::new(ast::PathPrefix::AbsolutePath { path }) - } else { - prefix.clone() + ast::Namespace(b'a' + d as u8) + } }; - 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(), - })) + Ok(ast::Path::Nested { + ns, + inner, + ident: ast::Ident { + dis: ast::Base62Number(disambiguated_data.disambiguator as u64), + u_ident: ast::UIdent(name.to_string()), + } + }) } fn path_generic_args( self, print_prefix: impl FnOnce(Self) -> Result, args: &[Kind<'tcx>], ) -> Result { - let mut path = print_prefix(self)?; + let prefix = 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!(), - }; + // 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 !ast_args.is_empty() { - bug!("mw::path_generic_args({:?}): prefix already has generic args: {:#?}", - args, path); + if args.clone().next().is_none() { + return Ok(prefix); } - for &arg in args { - match arg.unpack() { - UnpackedKind::Lifetime(_) => {} + let args = args.map(|arg| { + Ok(match arg.unpack() { + UnpackedKind::Lifetime(lt) => { + ast::GenericArg::Lifetime(lt.print(self)?) + } UnpackedKind::Type(ty) => { - ast_args.0.push(ty.print(self)?); + ast::GenericArg::Type(ty.print(self)?) } - UnpackedKind::Const(_) => return Err(Unsupported), - } - } + UnpackedKind::Const(ct) => { + ast::GenericArg::Const(ct.print(self)?) + } + }) + }).collect::, _>>()?; - Ok(path) + Ok(ast::Path::Generic { + inner: Arc::new(prefix), + args, + }) } } diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index 2caf41079f042..626ca8f6b5fc4 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -8,8 +8,8 @@ const WHITELISTED_SOURCES: &[&str] = &[ "\"registry+https://github.com/rust-lang/crates.io-index\"", "\"git+https://github.com/michaelwoerister/std-mangle-rs?\ - rev=2336dcdfcc91db3cdda18eda73aca488773ac6fc#\ - 2336dcdfcc91db3cdda18eda73aca488773ac6fc\"", + rev=e884304cfcb2f636db4d59ca8ad8fa95b983281c#\ + e884304cfcb2f636db4d59ca8ad8fa95b983281c\"", ]; /// Checks for external package sources. From 9cf35bfbe7b2610ff64c41668403fdb8f36c839c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 10 Apr 2019 08:33:31 +0300 Subject: [PATCH 09/10] rustc_codegen_utils: remove symbol name dumping/checking harness, and mw impl. --- Cargo.lock | 16 - src/librustc_codegen_utils/Cargo.toml | 4 - src/librustc_codegen_utils/symbol_names.rs | 18 +- .../symbol_names/dump.rs | 558 ------------------ .../symbol_names/legacy.rs | 9 +- src/librustc_codegen_utils/symbol_names/mw.rs | 421 ------------- src/librustc_codegen_utils/symbol_names/v0.rs | 19 +- src/tools/tidy/src/extdeps.rs | 4 - 8 files changed, 11 insertions(+), 1038 deletions(-) delete mode 100644 src/librustc_codegen_utils/symbol_names/dump.rs delete mode 100644 src/librustc_codegen_utils/symbol_names/mw.rs diff --git a/Cargo.lock b/Cargo.lock index d16a9a53ddcd2..a13bc0e74760a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2699,7 +2699,6 @@ 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=e884304cfcb2f636db4d59ca8ad8fa95b983281c)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -3336,14 +3335,6 @@ dependencies = [ "unwind 0.0.0", ] -[[package]] -name = "std-mangle-rs" -version = "0.1.0" -source = "git+https://github.com/michaelwoerister/std-mangle-rs?rev=e884304cfcb2f636db4d59ca8ad8fa95b983281c#e884304cfcb2f636db4d59ca8ad8fa95b983281c" -dependencies = [ - "unic-idna-punycode 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "string_cache" version = "0.7.3" @@ -3858,11 +3849,6 @@ 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" @@ -4368,7 +4354,6 @@ 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=e884304cfcb2f636db4d59ca8ad8fa95b983281c)" = "" "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" @@ -4412,7 +4397,6 @@ 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" diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 4023d79df3a96..268be2b109114 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -23,7 +23,3 @@ 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 = "e884304cfcb2f636db4d59ca8ad8fa95b983281c" diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 0b78b94866276..37847b1b0988f 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -100,9 +100,7 @@ use syntax_pos::symbol::InternedString; use log::debug; -mod dump; mod legacy; -mod mw; mod v0; pub fn provide(providers: &mut Providers<'_>) { @@ -221,19 +219,9 @@ fn symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> Interne }; let mangled = match mangling_version { - SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate, false), - SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate, true), + SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), + SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate), }; - let r = InternedString::intern(&mangled); - - dump::record( - tcx, - instance, - instantiating_crate, - mangling_version, - mangled, - ); - - r + InternedString::intern(&mangled) } diff --git a/src/librustc_codegen_utils/symbol_names/dump.rs b/src/librustc_codegen_utils/symbol_names/dump.rs deleted file mode 100644 index 0a60d3895e90c..0000000000000 --- a/src/librustc_codegen_utils/symbol_names/dump.rs +++ /dev/null @@ -1,558 +0,0 @@ -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 = { - std::env::var_os("RUST_SYMBOL_DUMP_DIR").map(PathBuf::from) -}); -thread_local!(static OUTPUT: RefCell> = RefCell::new(None)); - -pub fn record( - tcx: TyCtxt<'_, 'tcx, 'tcx>, - instance: Instance<'tcx>, - instantiating_crate: Option, - 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, -} - -// 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, -} - -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, - ns: char, - disambiguator: u64, - name: &str, - ) -> Result { - 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>, - ) -> Result { - 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 { - 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 { - 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>, - ) -> Result { - // 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 { - 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.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>, - ) -> Result { - 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, - _disambiguated_data: &DisambiguatedDefPathData, - _self_ty: Ty<'tcx>, - _trait_ref: Option>, - ) -> Result { - unreachable!() - } - fn path_append( - self, - print_prefix: impl FnOnce(Self) -> Result, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result { - 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, - args: &[Kind<'tcx>], - ) -> Result { - 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, - ) -> Result { - 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( - mut self, - value: &ty::Binder, - ) -> Result - 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) - } -} diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs index 5393eecb7f451..53682b9bdc2c8 100644 --- a/src/librustc_codegen_utils/symbol_names/legacy.rs +++ b/src/librustc_codegen_utils/symbol_names/legacy.rs @@ -18,7 +18,6 @@ pub(super) fn mangle( tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>, instantiating_crate: Option, - include_generic_args: bool, ) -> String { let def_id = instance.def_id(); @@ -57,17 +56,11 @@ 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, substs).unwrap(); + }.print_def_path(def_id, &[]).unwrap(); if instance.is_vtable_shim() { let _ = printer.write_str("{{vtable-shim}}"); diff --git a/src/librustc_codegen_utils/symbol_names/mw.rs b/src/librustc_codegen_utils/symbol_names/mw.rs deleted file mode 100644 index c0d8fe5445bd9..0000000000000 --- a/src/librustc_codegen_utils/symbol_names/mw.rs +++ /dev/null @@ -1,421 +0,0 @@ -use std_mangle_rs::ast; - -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_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, -) -> Result<(String, String), Unsupported> { - if instance.is_vtable_shim() { - return Err(Unsupported); - } - - let symbol = ast::Symbol { - version: None, - path: SymbolPrinter { tcx } - .print_def_path(instance.def_id(), instance.substs)?, - instantiating_crate: match instantiating_crate { - Some(instantiating_crate) => Some( - SymbolPrinter { tcx } - .path_crate(instantiating_crate)? - ), - None => None, - }, - }; - - let _ = symbol; - unimplemented!("missing compressor/mangler for mw symbol mangling"); - - /*let mut uncompressed = String::new(); - symbol.mangle(&mut uncompressed); - - let (compressed_symbol, _) = std_mangle_rs::compress::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 = ast::Path; - type Region = ast::Lifetime; - type Type = ast::Type; - type DynExistential = ast::DynBounds; - type Const = ast::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>, - ) -> Result { - 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 { - let i = match *region { - ty::ReErased => 0, - - // FIXME(eddyb) copy the implementation over to here. - ty::ReLateBound(_, ty::BrAnon(_)) => { - return Err(Unsupported); - } - - _ => bug!("mw: non-erased region `{:?}`", region), - }; - Ok(ast::Lifetime { - debruijn_index: ast::Base62Number(i), - }) - } - - fn print_type( - self, - ty: Ty<'tcx>, - ) -> Result { - macro_rules! basic { - ($name:ident) => (ast::Type::BasicType(ast::BasicType::$name)) - } - Ok(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), - - // Placeholders (should be demangled as `_`). - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | - ty::Infer(_) | ty::Error => basic!(Placeholder), - - ty::Ref(r, ty, mutbl) => { - let lt = if *r != ty::ReErased { - Some(r.print(self)?) - } else { - None - }; - let ty = Arc::new(ty.print(self)?); - match mutbl { - hir::MutImmutable => ast::Type::Ref(lt, ty), - hir::MutMutable => ast::Type::RefMut(lt, ty), - } - } - - ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::MutImmutable }) => { - ast::Type::RawPtrConst(Arc::new(ty.print(self)?)) - } - ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::MutMutable }) => { - ast::Type::RawPtrMut(Arc::new(ty.print(self)?)) - } - - ty::Array(ty, len) => { - ast::Type::Array(Arc::new(ty.print(self)?), Arc::new(len.print(self)?)) - } - ty::Slice(ty) => ast::Type::Slice(Arc::new(ty.print(self)?)), - - ty::Tuple(tys) => { - let tys = tys.iter() - .map(|k| k.expect_ty().print(self)) - .collect::, _>>()?; - 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(Arc::new(self.print_def_path(def_id, substs)?)) - } - ty::Foreign(def_id) => { - ast::Type::Named(Arc::new(self.print_def_path(def_id, &[])?)) - } - - ty::FnPtr(sig) => { - let mut param_types = sig.inputs().skip_binder().iter() - .map(|ty| ty.print(self)) - .collect::, _>>()?; - if sig.c_variadic() { - param_types.push(basic!(Ellipsis)); - } - let return_type = sig.output().skip_binder().print(self)?; - ast::Type::Fn(Arc::new(ast::FnSig { - binder: ast::Binder { - // FIXME(eddyb) needs to be implemented, see `print_region`. - count: ast::Base62Number(0), - }, - is_unsafe: sig.unsafety() == hir::Unsafety::Unsafe, - abi: match sig.abi() { - Abi::Rust => None, - Abi::C => Some(ast::Abi::C), - abi => Some(ast::Abi::Named(ast::UIdent(abi.name().replace('-', "_")))), - }, - param_types, - return_type, - })) - } - - ty::Dynamic(predicates, r) => { - let bounds = Arc::new(self.print_dyn_existential(predicates.skip_binder())?); - let lt = r.print(self)?; - ast::Type::DynTrait(bounds, lt) - } - - ty::GeneratorWitness(_) => { - bug!("mw: unexpected `GeneratorWitness`") - } - }) - } - - fn print_dyn_existential( - self, - predicates: &'tcx ty::List>, - ) -> Result { - let mut traits = vec![]; - for predicate in predicates { - match *predicate { - ty::ExistentialPredicate::Trait(trait_ref) => { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx.mk_infer(ty::FreshTy(0)); - let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); - traits.push(ast::DynTrait { - path: self.print_def_path(trait_ref.def_id, trait_ref.substs)?, - assoc_type_bindings: vec![], - }); - } - ty::ExistentialPredicate::Projection(projection) => { - let name = self.tcx.associated_item(projection.item_def_id).ident; - traits.last_mut().unwrap().assoc_type_bindings.push(ast::DynTraitAssocBinding { - ident: ast::UIdent(name.to_string()), - ty: projection.ty.print(self)?, - }); - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - traits.push(ast::DynTrait { - path: self.print_def_path(def_id, &[])?, - assoc_type_bindings: vec![], - }); - } - } - } - - Ok(ast::DynBounds { - binder: ast::Binder { - // FIXME(eddyb) needs to be implemented, see `print_region`. - count: ast::Base62Number(0), - }, - traits, - }) - } - - fn print_const( - self, - ct: &'tcx ty::Const<'tcx>, - ) -> Result { - match ct.ty.sty { - ty::Uint(_) => {} - _ => { - bug!("mw: unsupported constant of type `{}` ({:?})", - ct.ty, ct); - } - } - let ty = ct.ty.print(self)?; - - if let Some(bits) = ct.assert_bits(self.tcx, ty::ParamEnv::empty().and(ct.ty)) { - if bits as u64 as u128 != bits { - return Err(Unsupported); - } - Ok(ast::Const::Value(ty, bits as u64)) - } 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. - Ok(ast::Const::Placeholder(ty)) - } - } - - fn path_crate( - self, - cnum: CrateNum, - ) -> Result { - let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint(); - Ok(ast::Path::CrateRoot { - id: ast::Ident { - dis: ast::Base62Number(fingerprint.to_smaller_hash()), - u_ident: ast::UIdent(self.tcx.original_crate_name(cnum).to_string()), - }, - }) - } - fn path_qualified( - self, - self_ty: Ty<'tcx>, - trait_ref: Option>, - ) -> Result { - assert!(trait_ref.is_some()); - let trait_ref = trait_ref.unwrap(); - - // This is a default method in the trait declaration. - Ok(ast::Path::TraitDef { - self_type: self_ty.print(self)?, - trait_name: Arc::new(self.print_def_path(trait_ref.def_id, trait_ref.substs)?), - }) - } - - fn path_append_impl( - self, - print_prefix: impl FnOnce(Self) -> Result, - disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option>, - ) -> Result { - let impl_path = ast::ImplPath { - dis: Some(ast::Base62Number(disambiguated_data.disambiguator as u64)), - path: Arc::new(print_prefix(self)?), - }; - let self_type = self_ty.print(self)?; - match trait_ref { - Some(trait_ref) => Ok(ast::Path::TraitImpl { - impl_path, - self_type, - trait_name: Arc::new(self.print_def_path(trait_ref.def_id, trait_ref.substs)?), - }), - None => Ok(ast::Path::InherentImpl { - impl_path, - self_type, - }), - } - } - fn path_append( - self, - print_prefix: impl FnOnce(Self) -> Result, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result { - let inner = Arc::new(print_prefix(self)?); - - let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str()); - let name = name.as_ref().map_or("", |s| &s[..]); - let ns = match disambiguated_data.data { - DefPathData::ClosureExpr => ast::Namespace(b'C'), - - // Lowercase a-z are unspecified disambiguation categories. - _ => { - 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 name.bytes().enumerate() { - d = (d + i as u64 + b as u64) % 26; - } - - ast::Namespace(b'a' + d as u8) - } - }; - - Ok(ast::Path::Nested { - ns, - inner, - ident: ast::Ident { - dis: ast::Base62Number(disambiguated_data.disambiguator as u64), - u_ident: ast::UIdent(name.to_string()), - } - }) - } - fn path_generic_args( - self, - print_prefix: impl FnOnce(Self) -> Result, - args: &[Kind<'tcx>], - ) -> Result { - let prefix = 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_none() { - return Ok(prefix); - } - - let args = args.map(|arg| { - Ok(match arg.unpack() { - UnpackedKind::Lifetime(lt) => { - ast::GenericArg::Lifetime(lt.print(self)?) - } - UnpackedKind::Type(ty) => { - ast::GenericArg::Type(ty.print(self)?) - } - UnpackedKind::Const(ct) => { - ast::GenericArg::Const(ct.print(self)?) - } - }) - }).collect::, _>>()?; - - Ok(ast::Path::Generic { - inner: Arc::new(prefix), - args, - }) - } -} diff --git a/src/librustc_codegen_utils/symbol_names/v0.rs b/src/librustc_codegen_utils/symbol_names/v0.rs index dc985c8126c54..1615a097b3bf9 100644 --- a/src/librustc_codegen_utils/symbol_names/v0.rs +++ b/src/librustc_codegen_utils/symbol_names/v0.rs @@ -17,7 +17,6 @@ pub(super) fn mangle( tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>, instantiating_crate: Option, - compress: bool, ) -> String { let def_id = instance.def_id(); // FIXME(eddyb) this should ideally not be needed. @@ -27,17 +26,13 @@ pub(super) fn mangle( let prefix = "_R"; let mut cx = SymbolMangler { tcx, - compress: if compress { - Some(Box::new(CompressionCaches { - start_offset: prefix.len(), - - paths: FxHashMap::default(), - types: FxHashMap::default(), - consts: FxHashMap::default(), - })) - } else { - None - }, + compress: Some(Box::new(CompressionCaches { + start_offset: prefix.len(), + + paths: FxHashMap::default(), + types: FxHashMap::default(), + consts: FxHashMap::default(), + })), binders: vec![], out: String::from(prefix), }; diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index 626ca8f6b5fc4..52e263df5e3d3 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -6,10 +6,6 @@ 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=e884304cfcb2f636db4d59ca8ad8fa95b983281c#\ - e884304cfcb2f636db4d59ca8ad8fa95b983281c\"", ]; /// Checks for external package sources. From 3652ea4594918d5f4c7e7a073d3e3105c726d1ef Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 30 May 2019 03:56:45 +0300 Subject: [PATCH 10/10] test: add a more complex symbol-name testcase. --- src/test/ui/symbol-names/impl1.legacy.stderr | 42 +++++++++++++++----- src/test/ui/symbol-names/impl1.rs | 33 ++++++++++++++- src/test/ui/symbol-names/impl1.v0.stderr | 42 +++++++++++++++----- 3 files changed, 98 insertions(+), 19 deletions(-) diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr index 298841aa7c974..c1d22a919d900 100644 --- a/src/test/ui/symbol-names/impl1.legacy.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -1,50 +1,74 @@ error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE) - --> $DIR/impl1.rs:12:9 + --> $DIR/impl1.rs:13:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling(impl1::foo::Foo::bar::he53b9bee7600ed8d) - --> $DIR/impl1.rs:12:9 + --> $DIR/impl1.rs:13:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(impl1::foo::Foo::bar) - --> $DIR/impl1.rs:12:9 + --> $DIR/impl1.rs:13:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: def-path(foo::Foo::bar) - --> $DIR/impl1.rs:19:9 + --> $DIR/impl1.rs:20:9 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E) - --> $DIR/impl1.rs:30:9 + --> $DIR/impl1.rs:31:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling(impl1::bar::::baz::h86c41f0462d901d4) - --> $DIR/impl1.rs:30:9 + --> $DIR/impl1.rs:31:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(impl1::bar::::baz) - --> $DIR/impl1.rs:30:9 + --> $DIR/impl1.rs:31:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: def-path(bar::::baz) - --> $DIR/impl1.rs:37:9 + --> $DIR/impl1.rs:38:9 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: symbol-name(_ZN198_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h6f205aef6a8ccc7bE) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h6f205aef6a8ccc7b) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(<[&dyn Foo extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method) + --> $DIR/impl1.rs:70:13 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 2b30362e41977..9ed93bb98185a 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -1,8 +1,9 @@ +// ignore-tidy-linelength // revisions: legacy v0 //[legacy]compile-flags: -Z symbol-mangling-version=legacy //[v0]compile-flags: -Z symbol-mangling-version=v0 -#![feature(rustc_attrs)] +#![feature(optin_builtin_traits, rustc_attrs)] #![allow(dead_code)] mod foo { @@ -41,5 +42,35 @@ mod bar { } } +trait Foo { + type Assoc; +} + +auto trait AutoTrait {} + fn main() { + // Test closure mangling, and disambiguators. + || {}; + || { + trait Bar { + fn method(&self) {} + } + + // Test type mangling, by putting them in an `impl` header. + // FIXME(eddyb) test C varargs when `core::ffi::VaList` stops leaking into the signature + // (which is a problem because `core` has an unpredictable hash) - see also #44930. + impl Bar for [&'_ (dyn Foo + AutoTrait); 3] { + #[rustc_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN198_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method + //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method + //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method) + //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG0_KCRL0_hEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method) + //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo extern "C" fn(&'b u8)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method) + //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo extern "C" fn(&'b u8)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method) + #[rustc_def_path] + //[legacy]~^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method) + //[v0]~^^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method) + fn method(&self) {} + } + }; } diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr index 9f6314a6c29f0..1c4b256c9e933 100644 --- a/src/test/ui/symbol-names/impl1.v0.stderr +++ b/src/test/ui/symbol-names/impl1.v0.stderr @@ -1,50 +1,74 @@ error: symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar) - --> $DIR/impl1.rs:12:9 + --> $DIR/impl1.rs:13:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling(::bar) - --> $DIR/impl1.rs:12:9 + --> $DIR/impl1.rs:13:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(::bar) - --> $DIR/impl1.rs:12:9 + --> $DIR/impl1.rs:13:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: def-path(foo::Foo::bar) - --> $DIR/impl1.rs:19:9 + --> $DIR/impl1.rs:20:9 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ error: symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz) - --> $DIR/impl1.rs:30:9 + --> $DIR/impl1.rs:31:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling(::baz) - --> $DIR/impl1.rs:30:9 + --> $DIR/impl1.rs:31:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: demangling-alt(::baz) - --> $DIR/impl1.rs:30:9 + --> $DIR/impl1.rs:31:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ error: def-path(bar::::baz) - --> $DIR/impl1.rs:37:9 + --> $DIR/impl1.rs:38:9 | LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG0_KCRL0_hEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<[&dyn impl1[317d481089b8c8fe]::Foo extern "C" fn(&'b u8)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<[&dyn impl1::Foo extern "C" fn(&'b u8)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method) + --> $DIR/impl1.rs:63:13 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: def-path(<[&dyn Foo extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method) + --> $DIR/impl1.rs:70:13 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors