]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #69965 - mark-i-m:codegen-utils, r=eddyb
authorMazdak Farrokhzad <twingoow@gmail.com>
Sat, 21 Mar 2020 07:51:14 +0000 (08:51 +0100)
committerGitHub <noreply@github.com>
Sat, 21 Mar 2020 07:51:14 +0000 (08:51 +0100)
Refactorings to get rid of rustc_codegen_utils

r? @eddyb

cc #45276

After this, the only modules left in `rustc_codegen_utils` are
- `link`: a bunch of linking-related functions (many dealing with file names). These are mostly consumed by save analysis, rustc_driver, rustc_interface, and of course codegen. I assume they live here because we don't want a dependency of save analysis on codegen... Perhaps they can be moved to librustc?
- ~`symbol_names` and `symbol_names_test`: honestly it seems odd that `symbol_names_test` is not a submodule of `symbol_names`. It seems like these could honestly live in their own crate or move to librustc. Already name mangling is exported as the `symbol_name` query.~ (move it to its own crate)

I don't mind doing either of the above as part of this PR or a followup if you want.

38 files changed:
Cargo.lock
src/librustc/ty/mod.rs
src/librustc/util/bug.rs
src/librustc_codegen_llvm/Cargo.toml
src/librustc_codegen_llvm/lib.rs
src/librustc_codegen_ssa/Cargo.toml
src/librustc_codegen_ssa/back/link.rs
src/librustc_codegen_ssa/back/symbol_export.rs
src/librustc_codegen_ssa/base.rs
src/librustc_codegen_ssa/traits/backend.rs
src/librustc_codegen_ssa/traits/mod.rs
src/librustc_codegen_utils/Cargo.toml [deleted file]
src/librustc_codegen_utils/codegen_backend.rs [deleted file]
src/librustc_codegen_utils/lib.rs [deleted file]
src/librustc_codegen_utils/link.rs [deleted file]
src/librustc_codegen_utils/symbol_names.rs [deleted file]
src/librustc_codegen_utils/symbol_names/legacy.rs [deleted file]
src/librustc_codegen_utils/symbol_names/v0.rs [deleted file]
src/librustc_codegen_utils/symbol_names_test.rs [deleted file]
src/librustc_driver/Cargo.toml
src/librustc_driver/lib.rs
src/librustc_interface/Cargo.toml
src/librustc_interface/interface.rs
src/librustc_interface/passes.rs
src/librustc_interface/queries.rs
src/librustc_interface/util.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/lib.rs
src/librustc_save_analysis/Cargo.toml
src/librustc_save_analysis/lib.rs
src/librustc_session/lib.rs
src/librustc_session/output.rs [new file with mode: 0644]
src/librustc_symbol_mangling/Cargo.toml [new file with mode: 0644]
src/librustc_symbol_mangling/legacy.rs [new file with mode: 0644]
src/librustc_symbol_mangling/lib.rs [new file with mode: 0644]
src/librustc_symbol_mangling/test.rs [new file with mode: 0644]
src/librustc_symbol_mangling/v0.rs [new file with mode: 0644]
src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs

index 1b0516f71613efaf72ff13b62797996a6fa58731..04044c79bdaf93198a8083cb6e902dfb33612282 100644 (file)
@@ -3567,7 +3567,6 @@ dependencies = [
  "rustc_ast",
  "rustc_attr",
  "rustc_codegen_ssa",
- "rustc_codegen_utils",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_feature",
@@ -3598,37 +3597,21 @@ dependencies = [
  "rustc_apfloat",
  "rustc_ast",
  "rustc_attr",
- "rustc_codegen_utils",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fs_util",
  "rustc_hir",
  "rustc_incremental",
  "rustc_index",
+ "rustc_metadata",
  "rustc_session",
  "rustc_span",
+ "rustc_symbol_mangling",
  "rustc_target",
  "serialize",
  "tempfile",
 ]
 
-[[package]]
-name = "rustc_codegen_utils"
-version = "0.0.0"
-dependencies = [
- "log",
- "punycode",
- "rustc",
- "rustc-demangle",
- "rustc_ast",
- "rustc_data_structures",
- "rustc_hir",
- "rustc_metadata",
- "rustc_session",
- "rustc_span",
- "rustc_target",
-]
-
 [[package]]
 name = "rustc_data_structures"
 version = "0.0.0"
@@ -3665,7 +3648,6 @@ dependencies = [
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_codegen_ssa",
- "rustc_codegen_utils",
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_errors",
@@ -3814,7 +3796,6 @@ dependencies = [
  "rustc_builtin_macros",
  "rustc_codegen_llvm",
  "rustc_codegen_ssa",
- "rustc_codegen_utils",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_expand",
@@ -3832,6 +3813,7 @@ dependencies = [
  "rustc_resolve",
  "rustc_session",
  "rustc_span",
+ "rustc_symbol_mangling",
  "rustc_target",
  "rustc_trait_selection",
  "rustc_traits",
@@ -4071,7 +4053,6 @@ dependencies = [
  "rustc",
  "rustc_ast",
  "rustc_ast_pretty",
- "rustc_codegen_utils",
  "rustc_data_structures",
  "rustc_hir",
  "rustc_parse",
@@ -4112,6 +4093,23 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "rustc_symbol_mangling"
+version = "0.0.0"
+dependencies = [
+ "log",
+ "punycode",
+ "rustc",
+ "rustc-demangle",
+ "rustc_ast",
+ "rustc_data_structures",
+ "rustc_hir",
+ "rustc_metadata",
+ "rustc_session",
+ "rustc_span",
+ "rustc_target",
+]
+
 [[package]]
 name = "rustc_target"
 version = "0.0.0"
index 9e3853c51af13cb04afeb63fd9ad8d6b8058bfc8..eeacd6a6d83f6dda727570cfee51254c66e6a03e 100644 (file)
@@ -3148,6 +3148,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     context::provide(providers);
     erase_regions::provide(providers);
     layout::provide(providers);
+    super::util::bug::provide(providers);
     *providers = ty::query::Providers {
         trait_impls_of: trait_def::trait_impls_of_provider,
         all_local_trait_impls: trait_def::all_local_trait_impls,
index c12b2859f728ec752737dcdb9b2e7de5a4c44237..54cd8a29f947416cb4baccd920f05f0977bcb1d5 100644 (file)
@@ -1,6 +1,6 @@
 // These functions are used by macro expansion for bug! and span_bug!
 
-use crate::ty::tls;
+use crate::ty::{tls, TyCtxt};
 use rustc_span::{MultiSpan, Span};
 use std::fmt;
 
@@ -39,3 +39,17 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
     });
     unreachable!();
 }
+
+/// A query to trigger a `delay_span_bug`. Clearly, if one has a `tcx` one can already trigger a
+/// `delay_span_bug`, so what is the point of this? It exists to help us test `delay_span_bug`'s
+/// interactions with the query system and incremental.
+pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
+    tcx.sess.delay_span_bug(
+        tcx.def_span(key),
+        "delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]",
+    );
+}
+
+pub fn provide(providers: &mut crate::ty::query::Providers<'_>) {
+    *providers = crate::ty::query::Providers { trigger_delay_span_bug, ..*providers };
+}
index 0776cb19760d5620e1baa4861585603d4654143f..16ed0854abe6eabd1d529b7f5b901ff99f62cffd 100644 (file)
@@ -20,7 +20,6 @@ rustc = { path = "../librustc" }
 rustc-demangle = "0.1"
 rustc_attr = { path = "../librustc_attr" }
 rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
-rustc_codegen_utils = { path = "../librustc_codegen_utils" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
index fa730d289b16bca1dd37c2e3046087a9ec12c4f8..e36c80e15a5e0778312c86f1127bd7c0b0504890 100644 (file)
@@ -27,7 +27,6 @@
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule};
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc_errors::{FatalError, Handler};
 use rustc_serialize::json;
 use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest};
index 3181d568b013a98382a33029868badca2e0df9f7..299f4d2c6699897b48b90ecc0a5105b1f4577525 100644 (file)
@@ -25,7 +25,7 @@ rustc_span = { path = "../librustc_span" }
 rustc = { path = "../librustc" }
 rustc_apfloat = { path = "../librustc_apfloat" }
 rustc_attr = { path = "../librustc_attr" }
-rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_symbol_mangling = { path = "../librustc_symbol_mangling" }
 rustc_data_structures = { path = "../librustc_data_structures"}
 rustc_errors = { path = "../librustc_errors" }
 rustc_fs_util = { path = "../librustc_fs_util" }
@@ -34,3 +34,4 @@ rustc_incremental = { path = "../librustc_incremental" }
 rustc_index = { path = "../librustc_index" }
 rustc_target = { path = "../librustc_target" }
 rustc_session = { path = "../librustc_session" }
+rustc_metadata = { path = "../librustc_metadata" }
index af413d3cdfe6862ec25013ae7f902500101b4098..672b6e4aa4600c1e18ee055cd7ebb65456398573 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_session::config::{
     self, CFGuard, DebugInfo, OutputFilenames, OutputType, PrintRequest, Sanitizer,
 };
+use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
@@ -36,8 +37,6 @@
 use std::process::{ExitStatus, Output, Stdio};
 use std::str;
 
-pub use rustc_codegen_utils::link::*;
-
 pub fn remove(sess: &Session, path: &Path) {
     if let Err(e) = fs::remove_file(path) {
         sess.err(&format!("failed to remove {}: {}", path.display(), e));
index 8368d98884a5d5dfccde1621dec110fc42c7584c..8a2503ce16730679fd3e37bdcb19d3fb5ab8d9aa 100644 (file)
@@ -8,7 +8,6 @@
 use rustc::ty::Instance;
 use rustc::ty::{SymbolName, TyCtxt};
 use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
-use rustc_codegen_utils::symbol_names;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
@@ -423,17 +422,21 @@ pub fn symbol_name_for_instance_in_crate<'tcx>(
     // This is something instantiated in an upstream crate, so we have to use
     // the slower (because uncached) version of computing the symbol name.
     match symbol {
-        ExportedSymbol::NonGeneric(def_id) => symbol_names::symbol_name_for_instance_in_crate(
-            tcx,
-            Instance::mono(tcx, def_id),
-            instantiating_crate,
-        ),
-        ExportedSymbol::Generic(def_id, substs) => symbol_names::symbol_name_for_instance_in_crate(
-            tcx,
-            Instance::new(def_id, substs),
-            instantiating_crate,
-        ),
-        ExportedSymbol::DropGlue(ty) => symbol_names::symbol_name_for_instance_in_crate(
+        ExportedSymbol::NonGeneric(def_id) => {
+            rustc_symbol_mangling::symbol_name_for_instance_in_crate(
+                tcx,
+                Instance::mono(tcx, def_id),
+                instantiating_crate,
+            )
+        }
+        ExportedSymbol::Generic(def_id, substs) => {
+            rustc_symbol_mangling::symbol_name_for_instance_in_crate(
+                tcx,
+                Instance::new(def_id, substs),
+                instantiating_crate,
+            )
+        }
+        ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate(
             tcx,
             Instance::resolve_drop_in_place(tcx, ty),
             instantiating_crate,
index 5fd16cb121fdafbea5166729b7fc9d662c0ca728..834702a30099c9d427793c1e88a2a05d0d0d7c3b 100644 (file)
@@ -36,7 +36,6 @@
 use rustc::ty::query::Providers;
 use rustc::ty::{self, Instance, Ty, TyCtxt};
 use rustc_attr as attr;
-use rustc_codegen_utils::{check_for_rustc_errors_attr, symbol_names_test};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::print_time_passes_entry;
 use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
@@ -47,6 +46,7 @@
 use rustc_session::config::{self, EntryFnType, Lto};
 use rustc_session::Session;
 use rustc_span::Span;
+use rustc_symbol_mangling::test as symbol_names_test;
 
 use std::cmp;
 use std::ops::{Deref, DerefMut};
@@ -514,8 +514,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
     metadata: EncodedMetadata,
     need_metadata_module: bool,
 ) -> OngoingCodegen<B> {
-    check_for_rustc_errors_attr(tcx);
-
     // Skip crate items and just output metadata in -Z no-codegen mode.
     if tcx.sess.opts.debugging_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
         let ongoing_codegen = start_async_codegen(backend, tcx, metadata, 1);
index 7acae300a2f0276a7dca59695443e36f7a3a90c4..4e861f45ff7a50f476e76e45a842cd3cda9da95d 100644 (file)
@@ -2,15 +2,22 @@
 use super::CodegenObject;
 use crate::ModuleCodegen;
 
-use rustc::middle::cstore::EncodedMetadata;
+use rustc::dep_graph::DepGraph;
+use rustc::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
 use rustc::ty::layout::{HasTyCtxt, LayoutOf, TyLayout};
-use rustc::ty::Ty;
-use rustc::ty::TyCtxt;
+use rustc::ty::query::Providers;
+use rustc::ty::{Ty, TyCtxt};
+use rustc::util::common::ErrorReported;
 use rustc_ast::expand::allocator::AllocatorKind;
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
-use rustc_session::{config, Session};
+use rustc_session::{
+    config::{self, OutputFilenames, PrintRequest},
+    Session,
+};
 use rustc_span::symbol::Symbol;
 
+pub use rustc_data_structures::sync::MetadataRef;
+
+use std::any::Any;
 use std::sync::Arc;
 
 pub trait BackendTypes {
@@ -37,6 +44,50 @@ impl<'tcx, T> Backend<'tcx> for T where
 {
 }
 
+pub trait CodegenBackend {
+    fn init(&self, _sess: &Session) {}
+    fn print(&self, _req: PrintRequest, _sess: &Session) {}
+    fn target_features(&self, _sess: &Session) -> Vec<Symbol> {
+        vec![]
+    }
+    fn print_passes(&self) {}
+    fn print_version(&self) {}
+
+    fn metadata_loader(&self) -> Box<MetadataLoaderDyn>;
+    fn provide(&self, _providers: &mut Providers<'_>);
+    fn provide_extern(&self, _providers: &mut Providers<'_>);
+    fn codegen_crate<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        metadata: EncodedMetadata,
+        need_metadata_module: bool,
+    ) -> Box<dyn Any>;
+
+    /// This is called on the returned `Box<dyn Any>` from `codegen_backend`
+    ///
+    /// # Panics
+    ///
+    /// Panics when the passed `Box<dyn Any>` was not returned by `codegen_backend`.
+    fn join_codegen(
+        &self,
+        ongoing_codegen: Box<dyn Any>,
+        sess: &Session,
+        dep_graph: &DepGraph,
+    ) -> Result<Box<dyn Any>, ErrorReported>;
+
+    /// This is called on the returned `Box<dyn Any>` from `join_codegen`
+    ///
+    /// # Panics
+    ///
+    /// Panics when the passed `Box<dyn Any>` was not returned by `join_codegen`.
+    fn link(
+        &self,
+        sess: &Session,
+        codegen_results: Box<dyn Any>,
+        outputs: &OutputFilenames,
+    ) -> Result<(), ErrorReported>;
+}
+
 pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync {
     fn new_metadata(&self, sess: TyCtxt<'_>, mod_name: &str) -> Self::Module;
     fn write_compressed_metadata<'tcx>(
index d03ff8d4d37d8b7cf4aef1c6900a1fae0f867f40..1bc9f297ea1b122aa2db508be6e393b46232afd4 100644 (file)
@@ -29,7 +29,7 @@
 
 pub use self::abi::AbiBuilderMethods;
 pub use self::asm::{AsmBuilderMethods, AsmMethods};
-pub use self::backend::{Backend, BackendTypes, ExtraBackendMethods};
+pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods};
 pub use self::builder::{BuilderMethods, OverflowOp};
 pub use self::consts::ConstMethods;
 pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods};
diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml
deleted file mode 100644 (file)
index 7ab5902..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-name = "rustc_codegen_utils"
-version = "0.0.0"
-edition = "2018"
-
-[lib]
-name = "rustc_codegen_utils"
-path = "lib.rs"
-test = false
-
-[dependencies]
-log = "0.4"
-punycode = "0.4.0"
-rustc-demangle = "0.1.16"
-
-rustc_ast = { path = "../librustc_ast" }
-rustc_span = { path = "../librustc_span" }
-rustc = { path = "../librustc" }
-rustc_hir = { path = "../librustc_hir" }
-rustc_target = { path = "../librustc_target" }
-rustc_data_structures = { path = "../librustc_data_structures" }
-rustc_metadata = { path = "../librustc_metadata" }
-rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs
deleted file mode 100644 (file)
index 561692e..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-//! The Rust compiler.
-//!
-//! # Note
-//!
-//! This API is completely unstable and subject to change.
-
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-
-use std::any::Any;
-
-use rustc::dep_graph::DepGraph;
-use rustc::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
-use rustc::ty::query::Providers;
-use rustc::ty::TyCtxt;
-use rustc::util::common::ErrorReported;
-use rustc_session::config::{OutputFilenames, PrintRequest};
-use rustc_session::Session;
-use rustc_span::symbol::Symbol;
-
-pub use rustc_data_structures::sync::MetadataRef;
-
-pub trait CodegenBackend {
-    fn init(&self, _sess: &Session) {}
-    fn print(&self, _req: PrintRequest, _sess: &Session) {}
-    fn target_features(&self, _sess: &Session) -> Vec<Symbol> {
-        vec![]
-    }
-    fn print_passes(&self) {}
-    fn print_version(&self) {}
-
-    fn metadata_loader(&self) -> Box<MetadataLoaderDyn>;
-    fn provide(&self, _providers: &mut Providers<'_>);
-    fn provide_extern(&self, _providers: &mut Providers<'_>);
-    fn codegen_crate<'tcx>(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        metadata: EncodedMetadata,
-        need_metadata_module: bool,
-    ) -> Box<dyn Any>;
-
-    /// This is called on the returned `Box<dyn Any>` from `codegen_backend`
-    ///
-    /// # Panics
-    ///
-    /// Panics when the passed `Box<dyn Any>` was not returned by `codegen_backend`.
-    fn join_codegen(
-        &self,
-        ongoing_codegen: Box<dyn Any>,
-        sess: &Session,
-        dep_graph: &DepGraph,
-    ) -> Result<Box<dyn Any>, ErrorReported>;
-
-    /// This is called on the returned `Box<dyn Any>` from `join_codegen`
-    ///
-    /// # Panics
-    ///
-    /// Panics when the passed `Box<dyn Any>` was not returned by `join_codegen`.
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: Box<dyn Any>,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorReported>;
-}
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
deleted file mode 100644 (file)
index 38906bb..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-//! # Note
-//!
-//! This API is completely unstable and subject to change.
-
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(never_type)]
-#![feature(nll)]
-#![feature(in_band_lifetimes)]
-#![recursion_limit = "256"]
-
-#[macro_use]
-extern crate rustc;
-
-use rustc::ty::query::Providers;
-use rustc::ty::TyCtxt;
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_span::symbol::sym;
-
-pub mod codegen_backend;
-pub mod link;
-pub mod symbol_names;
-pub mod symbol_names_test;
-
-pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: DefId) {
-    tcx.sess.delay_span_bug(
-        tcx.def_span(key),
-        "delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]",
-    );
-}
-
-/// check for the #[rustc_error] annotation, which forces an
-/// error in codegen. This is used to write compile-fail tests
-/// that actually test that compilation succeeds without
-/// reporting an error.
-pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
-    if let Some((def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
-        let attrs = &*tcx.get_attrs(def_id);
-        for attr in attrs {
-            if attr.check_name(sym::rustc_error) {
-                match attr.meta_item_list() {
-                    // check if there is a #[rustc_error(delayed)]
-                    Some(list) => {
-                        if list.iter().any(|list_item| {
-                            list_item.ident().map(|i| i.name)
-                                == Some(sym::delay_span_bug_from_inside_query)
-                        }) {
-                            tcx.ensure().trigger_delay_span_bug(def_id);
-                        }
-                    }
-                    // bare #[rustc_error]
-                    None => {
-                        tcx.sess.span_fatal(
-                            tcx.def_span(def_id),
-                            "fatal error triggered by #[rustc_error]",
-                        );
-                    }
-                }
-            }
-        }
-    }
-}
-
-pub fn provide(providers: &mut Providers<'_>) {
-    crate::symbol_names::provide(providers);
-    *providers = Providers { trigger_delay_span_bug, ..*providers };
-}
diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs
deleted file mode 100644 (file)
index 1f53eec..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-use rustc_ast::{ast, attr};
-use rustc_session::config::{self, Input, OutputFilenames, OutputType};
-use rustc_session::Session;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
-use std::path::{Path, PathBuf};
-
-pub fn out_filename(
-    sess: &Session,
-    crate_type: config::CrateType,
-    outputs: &OutputFilenames,
-    crate_name: &str,
-) -> PathBuf {
-    let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
-    let out_filename = outputs
-        .outputs
-        .get(&OutputType::Exe)
-        .and_then(|s| s.to_owned())
-        .or_else(|| outputs.single_output_file.clone())
-        .unwrap_or(default_filename);
-
-    check_file_is_writeable(&out_filename, sess);
-
-    out_filename
-}
-
-// Make sure files are writeable.  Mac, FreeBSD, and Windows system linkers
-// check this already -- however, the Linux linker will happily overwrite a
-// read-only file.  We should be consistent.
-pub fn check_file_is_writeable(file: &Path, sess: &Session) {
-    if !is_writeable(file) {
-        sess.fatal(&format!(
-            "output file {} is not writeable -- check its \
-                            permissions",
-            file.display()
-        ));
-    }
-}
-
-fn is_writeable(p: &Path) -> bool {
-    match p.metadata() {
-        Err(..) => true,
-        Ok(m) => !m.permissions().readonly(),
-    }
-}
-
-pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String {
-    let validate = |s: String, span: Option<Span>| {
-        rustc_metadata::validate_crate_name(sess, &s, span);
-        s
-    };
-
-    // Look in attributes 100% of the time to make sure the attribute is marked
-    // as used. After doing this, however, we still prioritize a crate name from
-    // the command line over one found in the #[crate_name] attribute. If we
-    // find both we ensure that they're the same later on as well.
-    let attr_crate_name =
-        attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
-
-    if let Some(sess) = sess {
-        if let Some(ref s) = sess.opts.crate_name {
-            if let Some((attr, name)) = attr_crate_name {
-                if name.as_str() != *s {
-                    let msg = format!(
-                        "`--crate-name` and `#[crate_name]` are \
-                                       required to match, but `{}` != `{}`",
-                        s, name
-                    );
-                    sess.span_err(attr.span, &msg);
-                }
-            }
-            return validate(s.clone(), None);
-        }
-    }
-
-    if let Some((attr, s)) = attr_crate_name {
-        return validate(s.to_string(), Some(attr.span));
-    }
-    if let Input::File(ref path) = *input {
-        if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
-            if s.starts_with('-') {
-                let msg = format!(
-                    "crate names cannot start with a `-`, but \
-                                   `{}` has a leading hyphen",
-                    s
-                );
-                if let Some(sess) = sess {
-                    sess.err(&msg);
-                }
-            } else {
-                return validate(s.replace("-", "_"), None);
-            }
-        }
-    }
-
-    "rust_out".to_string()
-}
-
-pub fn filename_for_metadata(
-    sess: &Session,
-    crate_name: &str,
-    outputs: &OutputFilenames,
-) -> PathBuf {
-    let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
-
-    let out_filename = outputs
-        .single_output_file
-        .clone()
-        .unwrap_or_else(|| outputs.out_directory.join(&format!("lib{}.rmeta", libname)));
-
-    check_file_is_writeable(&out_filename, sess);
-
-    out_filename
-}
-
-pub fn filename_for_input(
-    sess: &Session,
-    crate_type: config::CrateType,
-    crate_name: &str,
-    outputs: &OutputFilenames,
-) -> PathBuf {
-    let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
-
-    match crate_type {
-        config::CrateType::Rlib => outputs.out_directory.join(&format!("lib{}.rlib", libname)),
-        config::CrateType::Cdylib | config::CrateType::ProcMacro | config::CrateType::Dylib => {
-            let (prefix, suffix) =
-                (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix);
-            outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
-        }
-        config::CrateType::Staticlib => {
-            let (prefix, suffix) = (
-                &sess.target.target.options.staticlib_prefix,
-                &sess.target.target.options.staticlib_suffix,
-            );
-            outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
-        }
-        config::CrateType::Executable => {
-            let suffix = &sess.target.target.options.exe_suffix;
-            let out_filename = outputs.path(OutputType::Exe);
-            if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) }
-        }
-    }
-}
-
-/// Returns default crate type for target
-///
-/// Default crate type is used when crate type isn't provided neither
-/// through cmd line arguments nor through crate attributes
-///
-/// It is CrateType::Executable for all platforms but iOS as there is no
-/// way to run iOS binaries anyway without jailbreaking and
-/// interaction with Rust code through static library is the only
-/// option for now
-pub fn default_output_for_target(sess: &Session) -> config::CrateType {
-    if !sess.target.target.options.executables {
-        config::CrateType::Staticlib
-    } else {
-        config::CrateType::Executable
-    }
-}
-
-/// Checks if target supports crate_type as output
-pub fn invalid_output_for_target(sess: &Session, crate_type: config::CrateType) -> bool {
-    match crate_type {
-        config::CrateType::Cdylib | config::CrateType::Dylib | config::CrateType::ProcMacro => {
-            if !sess.target.target.options.dynamic_linking {
-                return true;
-            }
-            if sess.crt_static(Some(crate_type))
-                && !sess.target.target.options.crt_static_allows_dylibs
-            {
-                return true;
-            }
-        }
-        _ => {}
-    }
-    if sess.target.target.options.only_cdylib {
-        match crate_type {
-            config::CrateType::ProcMacro | config::CrateType::Dylib => return true,
-            _ => {}
-        }
-    }
-    if !sess.target.target.options.executables {
-        if crate_type == config::CrateType::Executable {
-            return true;
-        }
-    }
-
-    false
-}
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
deleted file mode 100644 (file)
index eb3fe49..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-//! The Rust Linkage Model and Symbol Names
-//! =======================================
-//!
-//! The semantic model of Rust linkage is, broadly, that "there's no global
-//! namespace" between crates. Our aim is to preserve the illusion of this
-//! model despite the fact that it's not *quite* possible to implement on
-//! modern linkers. We initially didn't use system linkers at all, but have
-//! been convinced of their utility.
-//!
-//! There are a few issues to handle:
-//!
-//!  - Linkers operate on a flat namespace, so we have to flatten names.
-//!    We do this using the C++ namespace-mangling technique. Foo::bar
-//!    symbols and such.
-//!
-//!  - Symbols for distinct items with the same *name* need to get different
-//!    linkage-names. Examples of this are monomorphizations of functions or
-//!    items within anonymous scopes that end up having the same path.
-//!
-//!  - Symbols in different crates but with same names "within" the crate need
-//!    to get different linkage-names.
-//!
-//!  - Symbol names should be deterministic: Two consecutive runs of the
-//!    compiler over the same code base should produce the same symbol names for
-//!    the same items.
-//!
-//!  - Symbol names should not depend on any global properties of the code base,
-//!    so that small modifications to the code base do not result in all symbols
-//!    changing. In previous versions of the compiler, symbol names incorporated
-//!    the SVH (Stable Version Hash) of the crate. This scheme turned out to be
-//!    infeasible when used in conjunction with incremental compilation because
-//!    small code changes would invalidate all symbols generated previously.
-//!
-//!  - Even symbols from different versions of the same crate should be able to
-//!    live next to each other without conflict.
-//!
-//! In order to fulfill the above requirements the following scheme is used by
-//! the compiler:
-//!
-//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
-//! hash value into every exported symbol name. Anything that makes a difference
-//! to the symbol being named, but does not show up in the regular path needs to
-//! be fed into this hash:
-//!
-//! - Different monomorphizations of the same item have the same path but differ
-//!   in their concrete type parameters, so these parameters are part of the
-//!   data being digested for the symbol hash.
-//!
-//! - Rust allows items to be defined in anonymous scopes, such as in
-//!   `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
-//!   the path `foo::bar`, since the anonymous scopes do not contribute to the
-//!   path of an item. The compiler already handles this case via so-called
-//!   disambiguating `DefPaths` which use indices to distinguish items with the
-//!   same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
-//!   and `foo[0]::bar[1]`. In order to incorporate this disambiguation
-//!   information into the symbol name too, these indices are fed into the
-//!   symbol hash, so that the above two symbols would end up with different
-//!   hash values.
-//!
-//! The two measures described above suffice to avoid intra-crate conflicts. In
-//! order to also avoid inter-crate conflicts two more measures are taken:
-//!
-//! - The name of the crate containing the symbol is prepended to the symbol
-//!   name, i.e., symbols are "crate qualified". For example, a function `foo` in
-//!   module `bar` in crate `baz` would get a symbol name like
-//!   `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
-//!   simple conflicts between functions from different crates.
-//!
-//! - In order to be able to also use symbols from two versions of the same
-//!   crate (which naturally also have the same name), a stronger measure is
-//!   required: The compiler accepts an arbitrary "disambiguator" value via the
-//!   `-C metadata` command-line argument. This disambiguator is then fed into
-//!   the symbol hash of every exported item. Consequently, the symbols in two
-//!   identical crates but with different disambiguators are not in conflict
-//!   with each other. This facility is mainly intended to be used by build
-//!   tools like Cargo.
-//!
-//! A note on symbol name stability
-//! -------------------------------
-//! Previous versions of the compiler resorted to feeding NodeIds into the
-//! symbol hash in order to disambiguate between items with the same path. The
-//! current version of the name generation algorithm takes great care not to do
-//! that, since NodeIds are notoriously unstable: A small change to the
-//! code base will offset all NodeIds after the change and thus, much as using
-//! the SVH in the hash, invalidate an unbounded number of symbol names. This
-//! makes re-using previously compiled code for incremental compilation
-//! 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::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc::mir::mono::{InstantiationMode, MonoItem};
-use rustc::ty::query::Providers;
-use rustc::ty::subst::SubstsRef;
-use rustc::ty::{self, Instance, TyCtxt};
-use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
-use rustc_hir::Node;
-use rustc_session::config::SymbolManglingVersion;
-
-use rustc_span::symbol::Symbol;
-
-use log::debug;
-
-mod legacy;
-mod v0;
-
-/// This function computes the symbol name for the given `instance` and the
-/// given instantiating crate. That is, if you know that instance X is
-/// instantiated in crate Y, this is the symbol name this instance would have.
-pub fn symbol_name_for_instance_in_crate(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-    instantiating_crate: CrateNum,
-) -> String {
-    compute_symbol_name(tcx, instance, || instantiating_crate)
-}
-
-pub fn provide(providers: &mut Providers<'_>) {
-    *providers = Providers { symbol_name: symbol_name_provider, ..*providers };
-}
-
-// The `symbol_name` query provides the symbol name for calling a given
-// instance from the local crate. In particular, it will also look up the
-// correct symbol name of instances from upstream crates.
-fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName {
-    let symbol_name = compute_symbol_name(tcx, instance, || {
-        // This closure determines the instantiating crate for instances that
-        // need an instantiating-crate-suffix for their symbol name, in order
-        // to differentiate between local copies.
-        if is_generic(instance.substs) {
-            // For generics we might find re-usable upstream instances. If there
-            // is one, we rely on the symbol being instantiated locally.
-            instance.upstream_monomorphization(tcx).unwrap_or(LOCAL_CRATE)
-        } else {
-            // For non-generic things that need to avoid naming conflicts, we
-            // always instantiate a copy in the local crate.
-            LOCAL_CRATE
-        }
-    });
-
-    ty::SymbolName { name: Symbol::intern(&symbol_name) }
-}
-
-/// Computes the symbol name for the given instance. This function will call
-/// `compute_instantiating_crate` if it needs to factor the instantiating crate
-/// into the symbol name.
-fn compute_symbol_name(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-    compute_instantiating_crate: impl FnOnce() -> CrateNum,
-) -> String {
-    let def_id = instance.def_id();
-    let substs = instance.substs;
-
-    debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs);
-
-    let hir_id = tcx.hir().as_local_hir_id(def_id);
-
-    if def_id.is_local() {
-        if tcx.plugin_registrar_fn(LOCAL_CRATE) == Some(def_id) {
-            let disambiguator = tcx.sess.local_crate_disambiguator();
-            return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
-        }
-        if tcx.proc_macro_decls_static(LOCAL_CRATE) == Some(def_id) {
-            let disambiguator = tcx.sess.local_crate_disambiguator();
-            return tcx.sess.generate_proc_macro_decls_symbol(disambiguator);
-        }
-    }
-
-    // FIXME(eddyb) Precompute a custom symbol name based on attributes.
-    let is_foreign = if let Some(id) = hir_id {
-        match tcx.hir().get(id) {
-            Node::ForeignItem(_) => true,
-            _ => false,
-        }
-    } else {
-        tcx.is_foreign_item(def_id)
-    };
-
-    let attrs = tcx.codegen_fn_attrs(def_id);
-
-    // Foreign items by default use no mangling for their symbol name. There's a
-    // few exceptions to this rule though:
-    //
-    // * This can be overridden with the `#[link_name]` attribute
-    //
-    // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the
-    //   same-named symbol when imported from different wasm modules will get
-    //   hooked up incorrectly. As a result foreign symbols, on the wasm target,
-    //   with a wasm import module, get mangled. Additionally our codegen will
-    //   deduplicate symbols based purely on the symbol name, but for wasm this
-    //   isn't quite right because the same-named symbol on wasm can come from
-    //   different modules. For these reasons if `#[link(wasm_import_module)]`
-    //   is present we mangle everything on wasm because the demangled form will
-    //   show up in the `wasm-import-name` custom attribute in LLVM IR.
-    //
-    // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316
-    if is_foreign {
-        if tcx.sess.target.target.arch != "wasm32"
-            || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)
-        {
-            if let Some(name) = attrs.link_name {
-                return name.to_string();
-            }
-            return tcx.item_name(def_id).to_string();
-        }
-    }
-
-    if let Some(name) = attrs.export_name {
-        // Use provided name
-        return name.to_string();
-    }
-
-    if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
-        // Don't mangle
-        return tcx.item_name(def_id).to_string();
-    }
-
-    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(substs) ||
-
-        // 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,
-        };
-
-    let instantiating_crate =
-        if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None };
-
-    // 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)
-    };
-
-    match mangling_version {
-        SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
-        SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
-    }
-}
-
-fn is_generic(substs: SubstsRef<'_>) -> bool {
-    substs.non_erasable_generics().next().is_some()
-}
diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs
deleted file mode 100644 (file)
index 0dedda9..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
-use rustc::ich::NodeIdHashingMode;
-use rustc::mir::interpret::{ConstValue, Scalar};
-use rustc::ty::print::{PrettyPrinter, Print, Printer};
-use rustc::ty::subst::{GenericArg, GenericArgKind};
-use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
-use rustc::util::common::record_time;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::def_id::CrateNum;
-
-use log::debug;
-
-use std::fmt::{self, Write};
-use std::mem::{self, discriminant};
-
-pub(super) fn mangle(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-    instantiating_crate: Option<CrateNum>,
-) -> 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<'tcx>(
-    tcx: TyCtxt<'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<CrateNum>,
-) -> 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.kind {
-            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::<u64>()
-}
-
-// 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<'tcx> {
-    tcx: TyCtxt<'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> for SymbolPrinter<'tcx> {
-    type Error = fmt::Error;
-
-    type Path = Self;
-    type Region = Self;
-    type Type = Self;
-    type DynExistential = Self;
-    type Const = Self;
-
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
-        Ok(self)
-    }
-
-    fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
-        match ty.kind {
-            // 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, substs)
-            | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
-            _ => self.pretty_print_type(ty),
-        }
-    }
-
-    fn print_dyn_existential(
-        mut self,
-        predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
-    ) -> Result<Self::DynExistential, Self::Error> {
-        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<Self::Const, Self::Error> {
-        // only print integers
-        if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { .. })) = ct.val {
-            if ct.ty.is_integral() {
-                return self.pretty_print_const(ct, true);
-            }
-        }
-        self.write_str("_")?;
-        Ok(self)
-    }
-
-    fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-        self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
-        Ok(self)
-    }
-    fn path_qualified(
-        self,
-        self_ty: Ty<'tcx>,
-        trait_ref: Option<ty::TraitRef<'tcx>>,
-    ) -> Result<Self::Path, Self::Error> {
-        // Similar to `pretty_path_qualified`, but for the other
-        // types that are printed as paths (see `print_type` above).
-        match self_ty.kind {
-            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<Self::Path, Self::Error>,
-        _disambiguated_data: &DisambiguatedDefPathData,
-        self_ty: Ty<'tcx>,
-        trait_ref: Option<ty::TraitRef<'tcx>>,
-    ) -> Result<Self::Path, Self::Error> {
-        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<Self::Path, Self::Error>,
-        disambiguated_data: &DisambiguatedDefPathData,
-    ) -> Result<Self::Path, Self::Error> {
-        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_symbol().as_str())?;
-        Ok(self)
-    }
-    fn path_generic_args(
-        mut self,
-        print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
-        args: &[GenericArg<'tcx>],
-    ) -> Result<Self::Path, Self::Error> {
-        self = print_prefix(self)?;
-
-        let args = args.iter().cloned().filter(|arg| match arg.unpack() {
-            GenericArgKind::Lifetime(_) => false,
-            _ => true,
-        });
-
-        if args.clone().next().is_some() {
-            self.generic_delimiters(|cx| cx.comma_sep(args))
-        } else {
-            Ok(self)
-        }
-    }
-}
-
-impl PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
-    fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool {
-        false
-    }
-    fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error>
-    where
-        T: Print<'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<Self, Self::Error>,
-    ) -> Result<Self, Self::Error> {
-        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("$u6d$"),
-
-                // 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
deleted file mode 100644 (file)
index ce6d0d9..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
-use rustc::ty::print::{Print, Printer};
-use rustc::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
-use rustc_ast::ast::{FloatTy, IntTy, UintTy};
-use rustc_data_structures::base_n;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_target::spec::abi::Abi;
-
-use std::fmt::Write;
-use std::ops::Range;
-
-pub(super) fn mangle(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-    instantiating_crate: Option<CrateNum>,
-) -> 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: Some(Box::new(CompressionCaches {
-            start_offset: prefix.len(),
-
-            paths: FxHashMap::default(),
-            types: FxHashMap::default(),
-            consts: FxHashMap::default(),
-        })),
-        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 [GenericArg<'tcx>]), usize>,
-    types: FxHashMap<Ty<'tcx>, 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<u32>,
-}
-
-struct SymbolMangler<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    compress: Option<Box<CompressionCaches<'tcx>>>,
-    binders: Vec<BinderLevel>,
-    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 `<base-62-number>`, 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<Self, !>,
-        ns: char,
-        disambiguator: u64,
-        name: &str,
-    ) -> Result<Self, !> {
-        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, !> {
-        self.push("B");
-        self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64);
-        Ok(self)
-    }
-
-    fn in_binder<T>(
-        mut self,
-        value: &ty::Binder<T>,
-        print_value: impl FnOnce(Self, &T) -> Result<Self, !>,
-    ) -> Result<Self, !>
-    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) => {
-                        // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`.
-                        assert_ne!(i, 0);
-                        i - 1
-                    }
-                    _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
-                }
-            })
-            .max()
-            .map_or(0, |max| max + 1);
-
-        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> for SymbolMangler<'tcx> {
-    type Error = !;
-
-    type Path = Self;
-    type Region = Self;
-    type Type = Self;
-    type DynExistential = Self;
-    type Const = Self;
-
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn print_def_path(
-        mut self,
-        def_id: DefId,
-        substs: &'tcx [GenericArg<'tcx>],
-    ) -> Result<Self::Path, Self::Error> {
-        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 [GenericArg<'tcx>],
-        mut self_ty: Ty<'tcx>,
-        mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
-    ) -> Result<Self::Path, Self::Error> {
-        let key = self.tcx.def_key(impl_def_id);
-        let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
-
-        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<Self::Region, Self::Error> {
-        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)) => {
-                // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`.
-                assert_ne!(i, 0);
-                let i = i - 1;
-
-                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<Self::Type, Self::Error> {
-        // Basic types, never cached (single-character).
-        let basic_type = match ty.kind {
-            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.kind {
-            // 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::Mutability::Not => "R",
-                    hir::Mutability::Mut => "Q",
-                });
-                if *r != ty::ReErased {
-                    self = r.print(self)?;
-                }
-                self = ty.print(self)?;
-            }
-
-            ty::RawPtr(mt) => {
-                self.push(match mt.mutbl {
-                    hir::Mutability::Not => "P",
-                    hir::Mutability::Mut => "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, substs)
-            | ty::Generator(def_id, 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<ty::ExistentialPredicate<'tcx>>,
-    ) -> Result<Self::DynExistential, Self::Error> {
-        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<Self::Const, Self::Error> {
-        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.kind {
-            ty::Uint(_) => {}
-            _ => {
-                bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
-            }
-        }
-        self = ct.ty.print(self)?;
-
-        if let Some(bits) = ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), 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::Path, Self::Error> {
-        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<ty::TraitRef<'tcx>>,
-    ) -> Result<Self::Path, Self::Error> {
-        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<Self::Path, Self::Error>,
-        disambiguated_data: &DisambiguatedDefPathData,
-        self_ty: Ty<'tcx>,
-        trait_ref: Option<ty::TraitRef<'tcx>>,
-    ) -> Result<Self::Path, Self::Error> {
-        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<Self::Path, Self::Error>,
-        disambiguated_data: &DisambiguatedDefPathData,
-    ) -> Result<Self::Path, Self::Error> {
-        let ns = match disambiguated_data.data {
-            // 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',
-
-            // These should never show up as `path_append` arguments.
-            DefPathData::CrateRoot
-            | DefPathData::Misc
-            | DefPathData::Impl
-            | DefPathData::MacroNs(_)
-            | DefPathData::LifetimeNs(_) => {
-                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<Self::Path, Self::Error>,
-        args: &[GenericArg<'tcx>],
-    ) -> Result<Self::Path, Self::Error> {
-        // Don't print any regions if they're all erased.
-        let print_regions = args.iter().any(|arg| match arg.unpack() {
-            GenericArgKind::Lifetime(r) => *r != ty::ReErased,
-            _ => false,
-        });
-        let args = args.iter().cloned().filter(|arg| match arg.unpack() {
-            GenericArgKind::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() {
-                GenericArgKind::Lifetime(lt) => {
-                    self = lt.print(self)?;
-                }
-                GenericArgKind::Type(ty) => {
-                    self = ty.print(self)?;
-                }
-                GenericArgKind::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_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs
deleted file mode 100644 (file)
index 8f2f262..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-//! Walks the crate looking for items/impl-items/trait-items that have
-//! either a `rustc_symbol_name` or `rustc_def_path` attribute and
-//! generates an error giving, respectively, the symbol name or
-//! def-path. This is used for unit testing the code that generates
-//! paths etc in all kinds of annoying scenarios.
-
-use rustc::ty::{Instance, TyCtxt};
-use rustc_hir as hir;
-use rustc_span::symbol::{sym, Symbol};
-
-const SYMBOL_NAME: Symbol = sym::rustc_symbol_name;
-const DEF_PATH: Symbol = sym::rustc_def_path;
-
-pub fn report_symbol_names(tcx: TyCtxt<'_>) {
-    // if the `rustc_attrs` feature is not enabled, then the
-    // attributes we are interested in cannot be present anyway, so
-    // skip the walk.
-    if !tcx.features().rustc_attrs {
-        return;
-    }
-
-    tcx.dep_graph.with_ignore(|| {
-        let mut visitor = SymbolNamesTest { tcx };
-        tcx.hir().krate().visit_all_item_likes(&mut visitor);
-    })
-}
-
-struct SymbolNamesTest<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl SymbolNamesTest<'tcx> {
-    fn process_attrs(&mut self, hir_id: hir::HirId) {
-        let tcx = self.tcx;
-        let def_id = tcx.hir().local_def_id(hir_id);
-        for attr in tcx.get_attrs(def_id).iter() {
-            if attr.check_name(SYMBOL_NAME) {
-                // for now, can only use on monomorphic names
-                let instance = Instance::mono(tcx, def_id);
-                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.name.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));
-            }
-
-            // (*) The formatting of `tag({})` is chosen so that tests can elect
-            // to test the entirety of the string, if they choose, or else just
-            // some subset.
-        }
-    }
-}
-
-impl hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> {
-    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        self.process_attrs(item.hir_id);
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
-        self.process_attrs(trait_item.hir_id);
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
-        self.process_attrs(impl_item.hir_id);
-    }
-}
index 3e6449582319fedf36ef8bbb6d88d7b9c1114631..aec10ee5ef53776a8066b07e192f8004cde0686e 100644 (file)
@@ -27,13 +27,12 @@ rustc_parse = { path = "../librustc_parse" }
 rustc_plugin_impl = { path = "../librustc_plugin_impl" }
 rustc_save_analysis = { path = "../librustc_save_analysis" }
 rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
-rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_session = { path = "../librustc_session" }
 rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_interface = { path = "../librustc_interface" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 rustc_ast = { path = "../librustc_ast" }
 rustc_span = { path = "../librustc_span" }
-rustc_session = { path = "../librustc_session" }
 
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
index e3e076e769f5d14c91c39d98a059fa3b86ddcb9e..9097a72f36f49c4931971b6a2ac87de96a6a3738 100644 (file)
@@ -21,8 +21,8 @@
 use rustc::middle::cstore::MetadataLoader;
 use rustc::ty::TyCtxt;
 use rustc::util::common::ErrorReported;
-use rustc_codegen_ssa::CodegenResults;
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_ast::ast;
+use rustc_codegen_ssa::{traits::CodegenBackend, CodegenResults};
 use rustc_data_structures::profiling::print_time_passes_entry;
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::{
@@ -43,6 +43,8 @@
 use rustc_session::lint::{Lint, LintId};
 use rustc_session::{config, DiagnosticOutput, Session};
 use rustc_session::{early_error, early_warn};
+use rustc_span::source_map::{FileLoader, FileName};
+use rustc_span::symbol::sym;
 
 use std::borrow::Cow;
 use std::cmp::max;
 use std::str;
 use std::time::Instant;
 
-use rustc_ast::ast;
-use rustc_span::source_map::FileLoader;
-use rustc_span::symbol::sym;
-use rustc_span::FileName;
-
 mod args;
 pub mod pretty;
 
@@ -693,16 +690,15 @@ fn print_crate_info(
                     let t_outputs = rustc_interface::util::build_output_filenames(
                         input, odir, ofile, attrs, sess,
                     );
-                    let id = rustc_codegen_utils::link::find_crate_name(Some(sess), attrs, input);
+                    let id = rustc_session::output::find_crate_name(Some(sess), attrs, input);
                     if *req == PrintRequest::CrateName {
                         println!("{}", id);
                         continue;
                     }
                     let crate_types = collect_crate_types(sess, attrs);
                     for &style in &crate_types {
-                        let fname = rustc_codegen_utils::link::filename_for_input(
-                            sess, style, &id, &t_outputs,
-                        );
+                        let fname =
+                            rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
                         println!("{}", fname.file_name().unwrap().to_string_lossy());
                     }
                 }
index e84181f1d75e7238512b6b544ab3c40afaeabe03..2e055ff183f2c26eba1ff1ba8561f0ceda59dab1 100644 (file)
@@ -28,7 +28,7 @@ rustc_incremental = { path = "../librustc_incremental" }
 rustc_traits = { path = "../librustc_traits" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
-rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_symbol_mangling = { path = "../librustc_symbol_mangling" }
 rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true }
 rustc_hir = { path = "../librustc_hir" }
 rustc_infer = { path = "../librustc_infer" }
index c5ebcf0696fba163a68f8074bd7ba32902ab33b2..65a7a48d440bde2a758b951f66de818fcaa0d764 100644 (file)
@@ -5,7 +5,7 @@
 use rustc::util::common::ErrorReported;
 use rustc_ast::ast::{self, MetaItemKind};
 use rustc_ast::token;
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::OnDrop;
index ee323b204b7a01f28a3b965028d97dfc2f282a36..b7a5f2f4531e59f5129ffdbf8683e9665b066584 100644 (file)
@@ -14,8 +14,7 @@
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::{self, ast, visit};
 use rustc_codegen_ssa::back::link::emit_metadata;
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
-use rustc_codegen_utils::link::filename_for_metadata;
+use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::sync::{par_iter, Lrc, Once, ParallelIterator, WorkerLocal};
 use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
 use rustc_errors::PResult;
 use rustc_passes::{self, hir_stats, layout_test};
 use rustc_plugin_impl as plugin;
 use rustc_resolve::{Resolver, ResolverArenas};
-use rustc_session::config::{self, CrateType, Input, OutputFilenames, OutputType};
-use rustc_session::config::{PpMode, PpSourceMode};
+use rustc_session::config::{
+    self, CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode,
+};
 use rustc_session::lint;
+use rustc_session::output::{filename_for_input, filename_for_metadata};
 use rustc_session::search_paths::PathKind;
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
@@ -477,12 +478,7 @@ fn generated_output_paths(
             // by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
             OutputType::Exe if !exact_name => {
                 for crate_type in sess.crate_types.borrow().iter() {
-                    let p = ::rustc_codegen_utils::link::filename_for_input(
-                        sess,
-                        *crate_type,
-                        crate_name,
-                        outputs,
-                    );
+                    let p = filename_for_input(sess, *crate_type, crate_name, outputs);
                     out_filenames.push(p);
                 }
             }
@@ -682,7 +678,7 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) {
     rustc_ty::provide(providers);
     rustc_metadata::provide(providers);
     rustc_lint::provide(providers);
-    rustc_codegen_utils::provide(providers);
+    rustc_symbol_mangling::provide(providers);
     rustc_codegen_ssa::provide(providers);
 }
 
index 3514829dca7f777034b4a87c90e073f719195db8..3ca92216003d16976b78d44a5537aca33d109b16 100644 (file)
@@ -4,17 +4,18 @@
 use rustc::arena::Arena;
 use rustc::dep_graph::DepGraph;
 use rustc::ty::steal::Steal;
-use rustc::ty::{GlobalCtxt, ResolverOutputs};
+use rustc::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
 use rustc::util::common::ErrorReported;
 use rustc_ast::{self, ast};
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_hir::Crate;
 use rustc_incremental::DepGraphFuture;
 use rustc_lint::LintStore;
 use rustc_session::config::{OutputFilenames, OutputType};
-use rustc_session::Session;
+use rustc_session::{output::find_crate_name, Session};
+use rustc_span::symbol::sym;
 use std::any::Any;
 use std::cell::{Ref, RefCell, RefMut};
 use std::mem;
@@ -157,11 +158,7 @@ pub fn crate_name(&self) -> Result<&Query<String>> {
                 None => {
                     let parse_result = self.parse()?;
                     let krate = parse_result.peek();
-                    rustc_codegen_utils::link::find_crate_name(
-                        Some(self.session()),
-                        &krate.attrs,
-                        &self.compiler.input,
-                    )
+                    find_crate_name(Some(self.session()), &krate.attrs, &self.compiler.input)
                 }
             })
         })
@@ -277,11 +274,58 @@ pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
                 // Don't do code generation if there were any errors
                 self.session().compile_status()?;
 
+                // Hook for compile-fail tests.
+                Self::check_for_rustc_errors_attr(tcx);
+
                 Ok(passes::start_codegen(&***self.codegen_backend(), tcx, &*outputs.peek()))
             })
         })
     }
 
+    /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
+    /// to write compile-fail tests that actually test that compilation succeeds without reporting
+    /// an error.
+    fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
+        let def_id = match tcx.entry_fn(LOCAL_CRATE) {
+            Some((def_id, _)) => def_id,
+            _ => return,
+        };
+
+        let attrs = &*tcx.get_attrs(def_id);
+        let attrs = attrs.iter().filter(|attr| attr.check_name(sym::rustc_error));
+        for attr in attrs {
+            match attr.meta_item_list() {
+                // Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`.
+                Some(list)
+                    if list.iter().any(|list_item| {
+                        matches!(
+                            list_item.ident().map(|i| i.name),
+                            Some(sym::delay_span_bug_from_inside_query)
+                        )
+                    }) =>
+                {
+                    tcx.ensure().trigger_delay_span_bug(def_id);
+                }
+
+                // Bare `#[rustc_error]`.
+                None => {
+                    tcx.sess.span_fatal(
+                        tcx.def_span(def_id),
+                        "fatal error triggered by #[rustc_error]",
+                    );
+                }
+
+                // Some other attribute.
+                Some(_) => {
+                    tcx.sess.span_warn(
+                        tcx.def_span(def_id),
+                        "unexpected annotation used with `#[rustc_error(...)]!",
+                    );
+                }
+            }
+        }
+    }
+
     pub fn linker(&'tcx self) -> Result<Linker> {
         let dep_graph = self.dep_graph()?;
         let prepare_outputs = self.prepare_outputs()?;
index 5c4de9e7155c63c30f4a34cd86527d771fbb514a..c6f2d1b82fcf484da7c4cc4293d01106edd03d11 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_ast::ptr::P;
 use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_ast::{self, ast};
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[cfg(parallel_compiler)]
@@ -20,7 +20,7 @@
 use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::CrateConfig;
 use rustc_session::CrateDisambiguator;
-use rustc_session::{config, early_error, filesearch, DiagnosticOutput, Session};
+use rustc_session::{config, early_error, filesearch, output, DiagnosticOutput, Session};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap};
 use rustc_span::symbol::{sym, Symbol};
@@ -505,7 +505,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
     if base.is_empty() {
         base.extend(attr_types);
         if base.is_empty() {
-            base.push(::rustc_codegen_utils::link::default_output_for_target(session));
+            base.push(output::default_output_for_target(session));
         } else {
             base.sort();
             base.dedup();
@@ -513,7 +513,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
     }
 
     base.retain(|crate_type| {
-        let res = !::rustc_codegen_utils::link::invalid_output_for_target(session, *crate_type);
+        let res = !output::invalid_output_for_target(session, *crate_type);
 
         if !res {
             session.warn(&format!(
index 9b6e427abc1fd96abe04a3fa0ff91a790604c8d2..1f551583b0c863fbf0cc20159c734040c912fda6 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_index::vec::IndexVec;
 use rustc_session::config;
+use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_session::{CrateDisambiguator, Session};
 use rustc_span::edition::Edition;
@@ -852,11 +853,7 @@ pub fn process_extern_crate(
                 );
                 let name = match orig_name {
                     Some(orig_name) => {
-                        crate::validate_crate_name(
-                            Some(self.sess),
-                            &orig_name.as_str(),
-                            Some(item.span),
-                        );
+                        validate_crate_name(Some(self.sess), &orig_name.as_str(), Some(item.span));
                         orig_name
                     }
                     None => item.ident.name,
index e401dc0f6e7d49d698c1fd17143f42c219c90a94..2993aed2f8ab438062f6158d59c5acf63d1831de 100644 (file)
 pub mod creader;
 pub mod dynamic_lib;
 pub mod locator;
-
-pub fn validate_crate_name(
-    sess: Option<&rustc_session::Session>,
-    s: &str,
-    sp: Option<rustc_span::Span>,
-) {
-    let mut err_count = 0;
-    {
-        let mut say = |s: &str| {
-            match (sp, sess) {
-                (_, None) => bug!("{}", s),
-                (Some(sp), Some(sess)) => sess.span_err(sp, s),
-                (None, Some(sess)) => sess.err(s),
-            }
-            err_count += 1;
-        };
-        if s.is_empty() {
-            say("crate name must not be empty");
-        }
-        for c in s.chars() {
-            if c.is_alphanumeric() {
-                continue;
-            }
-            if c == '_' {
-                continue;
-            }
-            say(&format!("invalid character `{}` in crate name: `{}`", c, s));
-        }
-    }
-
-    if err_count > 0 {
-        sess.unwrap().abort_if_errors();
-    }
-}
index 4717664b6ba8000d4bf00850734bb7ddcb450889..de851d97727276e17c39b042ac7c06c0ae8262e7 100644 (file)
@@ -13,12 +13,11 @@ log = "0.4"
 rustc = { path = "../librustc" }
 rustc_ast_pretty = { path = "../librustc_ast_pretty" }
 rustc_data_structures = { path = "../librustc_data_structures" }
-rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_session = { path = "../librustc_session" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_parse = { path = "../librustc_parse" }
 serde_json = "1"
 rustc_ast = { path = "../librustc_ast" }
-rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
 rls-data = "0.19"
 rls-span = "0.5"
index 59084f19045454c1a3608d16a5860b483c842b23..bb717981a3be73afa4238a4027983c5040bd660d 100644 (file)
 use rustc_ast::util::comments::strip_doc_comment_decoration;
 use rustc_ast::visit::{self, Visitor};
 use rustc_ast_pretty::pprust::{self, param_to_string, ty_to_string};
-use rustc_codegen_utils::link::{filename_for_metadata, out_filename};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind as HirDefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::Node;
 use rustc_session::config::{CrateType, Input, OutputType};
+use rustc_session::output::{filename_for_metadata, out_filename};
 use rustc_span::source_map::Spanned;
 use rustc_span::*;
 
index 4101c32d547aad70bdae8246ab2394d89b0bc88b..cc4d525d62887c3a4dbf810978740a6da69a444a 100644 (file)
@@ -21,3 +21,5 @@
 
 mod session;
 pub use session::*;
+
+pub mod output;
diff --git a/src/librustc_session/output.rs b/src/librustc_session/output.rs
new file mode 100644 (file)
index 0000000..ba3d08c
--- /dev/null
@@ -0,0 +1,222 @@
+//! Related to out filenames of compilation (e.g. save analysis, binaries).
+use crate::config::{self, Input, OutputFilenames, OutputType};
+use crate::Session;
+use rustc_ast::{ast, attr};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+use std::path::{Path, PathBuf};
+
+pub fn out_filename(
+    sess: &Session,
+    crate_type: config::CrateType,
+    outputs: &OutputFilenames,
+    crate_name: &str,
+) -> PathBuf {
+    let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
+    let out_filename = outputs
+        .outputs
+        .get(&OutputType::Exe)
+        .and_then(|s| s.to_owned())
+        .or_else(|| outputs.single_output_file.clone())
+        .unwrap_or(default_filename);
+
+    check_file_is_writeable(&out_filename, sess);
+
+    out_filename
+}
+
+/// Make sure files are writeable.  Mac, FreeBSD, and Windows system linkers
+/// check this already -- however, the Linux linker will happily overwrite a
+/// read-only file.  We should be consistent.
+pub fn check_file_is_writeable(file: &Path, sess: &Session) {
+    if !is_writeable(file) {
+        sess.fatal(&format!(
+            "output file {} is not writeable -- check its \
+                            permissions",
+            file.display()
+        ));
+    }
+}
+
+fn is_writeable(p: &Path) -> bool {
+    match p.metadata() {
+        Err(..) => true,
+        Ok(m) => !m.permissions().readonly(),
+    }
+}
+
+pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String {
+    let validate = |s: String, span: Option<Span>| {
+        validate_crate_name(sess, &s, span);
+        s
+    };
+
+    // Look in attributes 100% of the time to make sure the attribute is marked
+    // as used. After doing this, however, we still prioritize a crate name from
+    // the command line over one found in the #[crate_name] attribute. If we
+    // find both we ensure that they're the same later on as well.
+    let attr_crate_name =
+        attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
+
+    if let Some(sess) = sess {
+        if let Some(ref s) = sess.opts.crate_name {
+            if let Some((attr, name)) = attr_crate_name {
+                if name.as_str() != *s {
+                    let msg = format!(
+                        "`--crate-name` and `#[crate_name]` are \
+                                       required to match, but `{}` != `{}`",
+                        s, name
+                    );
+                    sess.span_err(attr.span, &msg);
+                }
+            }
+            return validate(s.clone(), None);
+        }
+    }
+
+    if let Some((attr, s)) = attr_crate_name {
+        return validate(s.to_string(), Some(attr.span));
+    }
+    if let Input::File(ref path) = *input {
+        if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
+            if s.starts_with('-') {
+                let msg = format!(
+                    "crate names cannot start with a `-`, but \
+                                   `{}` has a leading hyphen",
+                    s
+                );
+                if let Some(sess) = sess {
+                    sess.err(&msg);
+                }
+            } else {
+                return validate(s.replace("-", "_"), None);
+            }
+        }
+    }
+
+    "rust_out".to_string()
+}
+
+pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
+    let mut err_count = 0;
+    {
+        let mut say = |s: &str| {
+            match (sp, sess) {
+                (_, None) => panic!("{}", s),
+                (Some(sp), Some(sess)) => sess.span_err(sp, s),
+                (None, Some(sess)) => sess.err(s),
+            }
+            err_count += 1;
+        };
+        if s.is_empty() {
+            say("crate name must not be empty");
+        }
+        for c in s.chars() {
+            if c.is_alphanumeric() {
+                continue;
+            }
+            if c == '_' {
+                continue;
+            }
+            say(&format!("invalid character `{}` in crate name: `{}`", c, s));
+        }
+    }
+
+    if err_count > 0 {
+        sess.unwrap().abort_if_errors();
+    }
+}
+
+pub fn filename_for_metadata(
+    sess: &Session,
+    crate_name: &str,
+    outputs: &OutputFilenames,
+) -> PathBuf {
+    let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
+
+    let out_filename = outputs
+        .single_output_file
+        .clone()
+        .unwrap_or_else(|| outputs.out_directory.join(&format!("lib{}.rmeta", libname)));
+
+    check_file_is_writeable(&out_filename, sess);
+
+    out_filename
+}
+
+pub fn filename_for_input(
+    sess: &Session,
+    crate_type: config::CrateType,
+    crate_name: &str,
+    outputs: &OutputFilenames,
+) -> PathBuf {
+    let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
+
+    match crate_type {
+        config::CrateType::Rlib => outputs.out_directory.join(&format!("lib{}.rlib", libname)),
+        config::CrateType::Cdylib | config::CrateType::ProcMacro | config::CrateType::Dylib => {
+            let (prefix, suffix) =
+                (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix);
+            outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
+        }
+        config::CrateType::Staticlib => {
+            let (prefix, suffix) = (
+                &sess.target.target.options.staticlib_prefix,
+                &sess.target.target.options.staticlib_suffix,
+            );
+            outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
+        }
+        config::CrateType::Executable => {
+            let suffix = &sess.target.target.options.exe_suffix;
+            let out_filename = outputs.path(OutputType::Exe);
+            if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) }
+        }
+    }
+}
+
+/// Returns default crate type for target
+///
+/// Default crate type is used when crate type isn't provided neither
+/// through cmd line arguments nor through crate attributes
+///
+/// It is CrateType::Executable for all platforms but iOS as there is no
+/// way to run iOS binaries anyway without jailbreaking and
+/// interaction with Rust code through static library is the only
+/// option for now
+pub fn default_output_for_target(sess: &Session) -> config::CrateType {
+    if !sess.target.target.options.executables {
+        config::CrateType::Staticlib
+    } else {
+        config::CrateType::Executable
+    }
+}
+
+/// Checks if target supports crate_type as output
+pub fn invalid_output_for_target(sess: &Session, crate_type: config::CrateType) -> bool {
+    match crate_type {
+        config::CrateType::Cdylib | config::CrateType::Dylib | config::CrateType::ProcMacro => {
+            if !sess.target.target.options.dynamic_linking {
+                return true;
+            }
+            if sess.crt_static(Some(crate_type))
+                && !sess.target.target.options.crt_static_allows_dylibs
+            {
+                return true;
+            }
+        }
+        _ => {}
+    }
+    if sess.target.target.options.only_cdylib {
+        match crate_type {
+            config::CrateType::ProcMacro | config::CrateType::Dylib => return true,
+            _ => {}
+        }
+    }
+    if !sess.target.target.options.executables {
+        if crate_type == config::CrateType::Executable {
+            return true;
+        }
+    }
+
+    false
+}
diff --git a/src/librustc_symbol_mangling/Cargo.toml b/src/librustc_symbol_mangling/Cargo.toml
new file mode 100644 (file)
index 0000000..1e4fc8f
--- /dev/null
@@ -0,0 +1,24 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_symbol_mangling"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+name = "rustc_symbol_mangling"
+path = "lib.rs"
+doctest = false
+
+[dependencies]
+log = "0.4"
+punycode = "0.4.0"
+rustc-demangle = "0.1.16"
+
+rustc_ast = { path = "../librustc_ast" }
+rustc_span = { path = "../librustc_span" }
+rustc = { path = "../librustc" }
+rustc_hir = { path = "../librustc_hir" }
+rustc_target = { path = "../librustc_target" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_metadata = { path = "../librustc_metadata" }
+rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc_symbol_mangling/legacy.rs b/src/librustc_symbol_mangling/legacy.rs
new file mode 100644 (file)
index 0000000..0dedda9
--- /dev/null
@@ -0,0 +1,434 @@
+use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
+use rustc::ich::NodeIdHashingMode;
+use rustc::mir::interpret::{ConstValue, Scalar};
+use rustc::ty::print::{PrettyPrinter, Print, Printer};
+use rustc::ty::subst::{GenericArg, GenericArgKind};
+use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc::util::common::record_time;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::def_id::CrateNum;
+
+use log::debug;
+
+use std::fmt::{self, Write};
+use std::mem::{self, discriminant};
+
+pub(super) fn mangle(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    instantiating_crate: Option<CrateNum>,
+) -> 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<'tcx>(
+    tcx: TyCtxt<'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<CrateNum>,
+) -> 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.kind {
+            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::<u64>()
+}
+
+// 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<'tcx> {
+    tcx: TyCtxt<'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> for SymbolPrinter<'tcx> {
+    type Error = fmt::Error;
+
+    type Path = Self;
+    type Region = Self;
+    type Type = Self;
+    type DynExistential = Self;
+    type Const = Self;
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
+        Ok(self)
+    }
+
+    fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+        match ty.kind {
+            // 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, substs)
+            | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
+            _ => self.pretty_print_type(ty),
+        }
+    }
+
+    fn print_dyn_existential(
+        mut self,
+        predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+    ) -> Result<Self::DynExistential, Self::Error> {
+        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<Self::Const, Self::Error> {
+        // only print integers
+        if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { .. })) = ct.val {
+            if ct.ty.is_integral() {
+                return self.pretty_print_const(ct, true);
+            }
+        }
+        self.write_str("_")?;
+        Ok(self)
+    }
+
+    fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+        self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
+        Ok(self)
+    }
+    fn path_qualified(
+        self,
+        self_ty: Ty<'tcx>,
+        trait_ref: Option<ty::TraitRef<'tcx>>,
+    ) -> Result<Self::Path, Self::Error> {
+        // Similar to `pretty_path_qualified`, but for the other
+        // types that are printed as paths (see `print_type` above).
+        match self_ty.kind {
+            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<Self::Path, Self::Error>,
+        _disambiguated_data: &DisambiguatedDefPathData,
+        self_ty: Ty<'tcx>,
+        trait_ref: Option<ty::TraitRef<'tcx>>,
+    ) -> Result<Self::Path, Self::Error> {
+        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<Self::Path, Self::Error>,
+        disambiguated_data: &DisambiguatedDefPathData,
+    ) -> Result<Self::Path, Self::Error> {
+        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_symbol().as_str())?;
+        Ok(self)
+    }
+    fn path_generic_args(
+        mut self,
+        print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+        args: &[GenericArg<'tcx>],
+    ) -> Result<Self::Path, Self::Error> {
+        self = print_prefix(self)?;
+
+        let args = args.iter().cloned().filter(|arg| match arg.unpack() {
+            GenericArgKind::Lifetime(_) => false,
+            _ => true,
+        });
+
+        if args.clone().next().is_some() {
+            self.generic_delimiters(|cx| cx.comma_sep(args))
+        } else {
+            Ok(self)
+        }
+    }
+}
+
+impl PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
+    fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool {
+        false
+    }
+    fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error>
+    where
+        T: Print<'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<Self, Self::Error>,
+    ) -> Result<Self, Self::Error> {
+        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("$u6d$"),
+
+                // 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_symbol_mangling/lib.rs b/src/librustc_symbol_mangling/lib.rs
new file mode 100644 (file)
index 0000000..26cb341
--- /dev/null
@@ -0,0 +1,273 @@
+//! The Rust Linkage Model and Symbol Names
+//! =======================================
+//!
+//! The semantic model of Rust linkage is, broadly, that "there's no global
+//! namespace" between crates. Our aim is to preserve the illusion of this
+//! model despite the fact that it's not *quite* possible to implement on
+//! modern linkers. We initially didn't use system linkers at all, but have
+//! been convinced of their utility.
+//!
+//! There are a few issues to handle:
+//!
+//!  - Linkers operate on a flat namespace, so we have to flatten names.
+//!    We do this using the C++ namespace-mangling technique. Foo::bar
+//!    symbols and such.
+//!
+//!  - Symbols for distinct items with the same *name* need to get different
+//!    linkage-names. Examples of this are monomorphizations of functions or
+//!    items within anonymous scopes that end up having the same path.
+//!
+//!  - Symbols in different crates but with same names "within" the crate need
+//!    to get different linkage-names.
+//!
+//!  - Symbol names should be deterministic: Two consecutive runs of the
+//!    compiler over the same code base should produce the same symbol names for
+//!    the same items.
+//!
+//!  - Symbol names should not depend on any global properties of the code base,
+//!    so that small modifications to the code base do not result in all symbols
+//!    changing. In previous versions of the compiler, symbol names incorporated
+//!    the SVH (Stable Version Hash) of the crate. This scheme turned out to be
+//!    infeasible when used in conjunction with incremental compilation because
+//!    small code changes would invalidate all symbols generated previously.
+//!
+//!  - Even symbols from different versions of the same crate should be able to
+//!    live next to each other without conflict.
+//!
+//! In order to fulfill the above requirements the following scheme is used by
+//! the compiler:
+//!
+//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
+//! hash value into every exported symbol name. Anything that makes a difference
+//! to the symbol being named, but does not show up in the regular path needs to
+//! be fed into this hash:
+//!
+//! - Different monomorphizations of the same item have the same path but differ
+//!   in their concrete type parameters, so these parameters are part of the
+//!   data being digested for the symbol hash.
+//!
+//! - Rust allows items to be defined in anonymous scopes, such as in
+//!   `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
+//!   the path `foo::bar`, since the anonymous scopes do not contribute to the
+//!   path of an item. The compiler already handles this case via so-called
+//!   disambiguating `DefPaths` which use indices to distinguish items with the
+//!   same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
+//!   and `foo[0]::bar[1]`. In order to incorporate this disambiguation
+//!   information into the symbol name too, these indices are fed into the
+//!   symbol hash, so that the above two symbols would end up with different
+//!   hash values.
+//!
+//! The two measures described above suffice to avoid intra-crate conflicts. In
+//! order to also avoid inter-crate conflicts two more measures are taken:
+//!
+//! - The name of the crate containing the symbol is prepended to the symbol
+//!   name, i.e., symbols are "crate qualified". For example, a function `foo` in
+//!   module `bar` in crate `baz` would get a symbol name like
+//!   `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
+//!   simple conflicts between functions from different crates.
+//!
+//! - In order to be able to also use symbols from two versions of the same
+//!   crate (which naturally also have the same name), a stronger measure is
+//!   required: The compiler accepts an arbitrary "disambiguator" value via the
+//!   `-C metadata` command-line argument. This disambiguator is then fed into
+//!   the symbol hash of every exported item. Consequently, the symbols in two
+//!   identical crates but with different disambiguators are not in conflict
+//!   with each other. This facility is mainly intended to be used by build
+//!   tools like Cargo.
+//!
+//! A note on symbol name stability
+//! -------------------------------
+//! Previous versions of the compiler resorted to feeding NodeIds into the
+//! symbol hash in order to disambiguate between items with the same path. The
+//! current version of the name generation algorithm takes great care not to do
+//! that, since NodeIds are notoriously unstable: A small change to the
+//! code base will offset all NodeIds after the change and thus, much as using
+//! the SVH in the hash, invalidate an unbounded number of symbol names. This
+//! makes re-using previously compiled code for incremental compilation
+//! virtually impossible. Thus, symbol hash generation exclusively relies on
+//! DefPaths which are much more robust in the face of changes to the code base.
+
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(never_type)]
+#![feature(nll)]
+#![feature(in_band_lifetimes)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate rustc;
+
+use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc::mir::mono::{InstantiationMode, MonoItem};
+use rustc::ty::query::Providers;
+use rustc::ty::subst::SubstsRef;
+use rustc::ty::{self, Instance, TyCtxt};
+use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_hir::Node;
+use rustc_session::config::SymbolManglingVersion;
+
+use rustc_span::symbol::Symbol;
+
+use log::debug;
+
+mod legacy;
+mod v0;
+
+pub mod test;
+
+/// This function computes the symbol name for the given `instance` and the
+/// given instantiating crate. That is, if you know that instance X is
+/// instantiated in crate Y, this is the symbol name this instance would have.
+pub fn symbol_name_for_instance_in_crate(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    instantiating_crate: CrateNum,
+) -> String {
+    compute_symbol_name(tcx, instance, || instantiating_crate)
+}
+
+pub fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers { symbol_name: symbol_name_provider, ..*providers };
+}
+
+// The `symbol_name` query provides the symbol name for calling a given
+// instance from the local crate. In particular, it will also look up the
+// correct symbol name of instances from upstream crates.
+fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName {
+    let symbol_name = compute_symbol_name(tcx, instance, || {
+        // This closure determines the instantiating crate for instances that
+        // need an instantiating-crate-suffix for their symbol name, in order
+        // to differentiate between local copies.
+        if is_generic(instance.substs) {
+            // For generics we might find re-usable upstream instances. If there
+            // is one, we rely on the symbol being instantiated locally.
+            instance.upstream_monomorphization(tcx).unwrap_or(LOCAL_CRATE)
+        } else {
+            // For non-generic things that need to avoid naming conflicts, we
+            // always instantiate a copy in the local crate.
+            LOCAL_CRATE
+        }
+    });
+
+    ty::SymbolName { name: Symbol::intern(&symbol_name) }
+}
+
+/// Computes the symbol name for the given instance. This function will call
+/// `compute_instantiating_crate` if it needs to factor the instantiating crate
+/// into the symbol name.
+fn compute_symbol_name(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    compute_instantiating_crate: impl FnOnce() -> CrateNum,
+) -> String {
+    let def_id = instance.def_id();
+    let substs = instance.substs;
+
+    debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs);
+
+    let hir_id = tcx.hir().as_local_hir_id(def_id);
+
+    if def_id.is_local() {
+        if tcx.plugin_registrar_fn(LOCAL_CRATE) == Some(def_id) {
+            let disambiguator = tcx.sess.local_crate_disambiguator();
+            return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
+        }
+        if tcx.proc_macro_decls_static(LOCAL_CRATE) == Some(def_id) {
+            let disambiguator = tcx.sess.local_crate_disambiguator();
+            return tcx.sess.generate_proc_macro_decls_symbol(disambiguator);
+        }
+    }
+
+    // FIXME(eddyb) Precompute a custom symbol name based on attributes.
+    let is_foreign = if let Some(id) = hir_id {
+        match tcx.hir().get(id) {
+            Node::ForeignItem(_) => true,
+            _ => false,
+        }
+    } else {
+        tcx.is_foreign_item(def_id)
+    };
+
+    let attrs = tcx.codegen_fn_attrs(def_id);
+
+    // Foreign items by default use no mangling for their symbol name. There's a
+    // few exceptions to this rule though:
+    //
+    // * This can be overridden with the `#[link_name]` attribute
+    //
+    // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the
+    //   same-named symbol when imported from different wasm modules will get
+    //   hooked up incorrectly. As a result foreign symbols, on the wasm target,
+    //   with a wasm import module, get mangled. Additionally our codegen will
+    //   deduplicate symbols based purely on the symbol name, but for wasm this
+    //   isn't quite right because the same-named symbol on wasm can come from
+    //   different modules. For these reasons if `#[link(wasm_import_module)]`
+    //   is present we mangle everything on wasm because the demangled form will
+    //   show up in the `wasm-import-name` custom attribute in LLVM IR.
+    //
+    // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316
+    if is_foreign {
+        if tcx.sess.target.target.arch != "wasm32"
+            || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)
+        {
+            if let Some(name) = attrs.link_name {
+                return name.to_string();
+            }
+            return tcx.item_name(def_id).to_string();
+        }
+    }
+
+    if let Some(name) = attrs.export_name {
+        // Use provided name
+        return name.to_string();
+    }
+
+    if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
+        // Don't mangle
+        return tcx.item_name(def_id).to_string();
+    }
+
+    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(substs) ||
+
+        // 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,
+        };
+
+    let instantiating_crate =
+        if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None };
+
+    // 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)
+    };
+
+    match mangling_version {
+        SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
+        SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
+    }
+}
+
+fn is_generic(substs: SubstsRef<'_>) -> bool {
+    substs.non_erasable_generics().next().is_some()
+}
diff --git a/src/librustc_symbol_mangling/test.rs b/src/librustc_symbol_mangling/test.rs
new file mode 100644 (file)
index 0000000..8f2f262
--- /dev/null
@@ -0,0 +1,70 @@
+//! Walks the crate looking for items/impl-items/trait-items that have
+//! either a `rustc_symbol_name` or `rustc_def_path` attribute and
+//! generates an error giving, respectively, the symbol name or
+//! def-path. This is used for unit testing the code that generates
+//! paths etc in all kinds of annoying scenarios.
+
+use rustc::ty::{Instance, TyCtxt};
+use rustc_hir as hir;
+use rustc_span::symbol::{sym, Symbol};
+
+const SYMBOL_NAME: Symbol = sym::rustc_symbol_name;
+const DEF_PATH: Symbol = sym::rustc_def_path;
+
+pub fn report_symbol_names(tcx: TyCtxt<'_>) {
+    // if the `rustc_attrs` feature is not enabled, then the
+    // attributes we are interested in cannot be present anyway, so
+    // skip the walk.
+    if !tcx.features().rustc_attrs {
+        return;
+    }
+
+    tcx.dep_graph.with_ignore(|| {
+        let mut visitor = SymbolNamesTest { tcx };
+        tcx.hir().krate().visit_all_item_likes(&mut visitor);
+    })
+}
+
+struct SymbolNamesTest<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl SymbolNamesTest<'tcx> {
+    fn process_attrs(&mut self, hir_id: hir::HirId) {
+        let tcx = self.tcx;
+        let def_id = tcx.hir().local_def_id(hir_id);
+        for attr in tcx.get_attrs(def_id).iter() {
+            if attr.check_name(SYMBOL_NAME) {
+                // for now, can only use on monomorphic names
+                let instance = Instance::mono(tcx, def_id);
+                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.name.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));
+            }
+
+            // (*) The formatting of `tag({})` is chosen so that tests can elect
+            // to test the entirety of the string, if they choose, or else just
+            // some subset.
+        }
+    }
+}
+
+impl hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> {
+    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+        self.process_attrs(item.hir_id);
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
+        self.process_attrs(trait_item.hir_id);
+    }
+
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
+        self.process_attrs(impl_item.hir_id);
+    }
+}
diff --git a/src/librustc_symbol_mangling/v0.rs b/src/librustc_symbol_mangling/v0.rs
new file mode 100644 (file)
index 0000000..ce6d0d9
--- /dev/null
@@ -0,0 +1,641 @@
+use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
+use rustc::ty::print::{Print, Printer};
+use rustc::ty::subst::{GenericArg, GenericArgKind, Subst};
+use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_ast::ast::{FloatTy, IntTy, UintTy};
+use rustc_data_structures::base_n;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir as hir;
+use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_target::spec::abi::Abi;
+
+use std::fmt::Write;
+use std::ops::Range;
+
+pub(super) fn mangle(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    instantiating_crate: Option<CrateNum>,
+) -> 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: Some(Box::new(CompressionCaches {
+            start_offset: prefix.len(),
+
+            paths: FxHashMap::default(),
+            types: FxHashMap::default(),
+            consts: FxHashMap::default(),
+        })),
+        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 [GenericArg<'tcx>]), usize>,
+    types: FxHashMap<Ty<'tcx>, 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<u32>,
+}
+
+struct SymbolMangler<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    compress: Option<Box<CompressionCaches<'tcx>>>,
+    binders: Vec<BinderLevel>,
+    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 `<base-62-number>`, 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<Self, !>,
+        ns: char,
+        disambiguator: u64,
+        name: &str,
+    ) -> Result<Self, !> {
+        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, !> {
+        self.push("B");
+        self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64);
+        Ok(self)
+    }
+
+    fn in_binder<T>(
+        mut self,
+        value: &ty::Binder<T>,
+        print_value: impl FnOnce(Self, &T) -> Result<Self, !>,
+    ) -> Result<Self, !>
+    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) => {
+                        // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`.
+                        assert_ne!(i, 0);
+                        i - 1
+                    }
+                    _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
+                }
+            })
+            .max()
+            .map_or(0, |max| max + 1);
+
+        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> for SymbolMangler<'tcx> {
+    type Error = !;
+
+    type Path = Self;
+    type Region = Self;
+    type Type = Self;
+    type DynExistential = Self;
+    type Const = Self;
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn print_def_path(
+        mut self,
+        def_id: DefId,
+        substs: &'tcx [GenericArg<'tcx>],
+    ) -> Result<Self::Path, Self::Error> {
+        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 [GenericArg<'tcx>],
+        mut self_ty: Ty<'tcx>,
+        mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
+    ) -> Result<Self::Path, Self::Error> {
+        let key = self.tcx.def_key(impl_def_id);
+        let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
+
+        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<Self::Region, Self::Error> {
+        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)) => {
+                // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`.
+                assert_ne!(i, 0);
+                let i = i - 1;
+
+                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<Self::Type, Self::Error> {
+        // Basic types, never cached (single-character).
+        let basic_type = match ty.kind {
+            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.kind {
+            // 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::Mutability::Not => "R",
+                    hir::Mutability::Mut => "Q",
+                });
+                if *r != ty::ReErased {
+                    self = r.print(self)?;
+                }
+                self = ty.print(self)?;
+            }
+
+            ty::RawPtr(mt) => {
+                self.push(match mt.mutbl {
+                    hir::Mutability::Not => "P",
+                    hir::Mutability::Mut => "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, substs)
+            | ty::Generator(def_id, 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<ty::ExistentialPredicate<'tcx>>,
+    ) -> Result<Self::DynExistential, Self::Error> {
+        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<Self::Const, Self::Error> {
+        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.kind {
+            ty::Uint(_) => {}
+            _ => {
+                bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
+            }
+        }
+        self = ct.ty.print(self)?;
+
+        if let Some(bits) = ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), 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::Path, Self::Error> {
+        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<ty::TraitRef<'tcx>>,
+    ) -> Result<Self::Path, Self::Error> {
+        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<Self::Path, Self::Error>,
+        disambiguated_data: &DisambiguatedDefPathData,
+        self_ty: Ty<'tcx>,
+        trait_ref: Option<ty::TraitRef<'tcx>>,
+    ) -> Result<Self::Path, Self::Error> {
+        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<Self::Path, Self::Error>,
+        disambiguated_data: &DisambiguatedDefPathData,
+    ) -> Result<Self::Path, Self::Error> {
+        let ns = match disambiguated_data.data {
+            // 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',
+
+            // These should never show up as `path_append` arguments.
+            DefPathData::CrateRoot
+            | DefPathData::Misc
+            | DefPathData::Impl
+            | DefPathData::MacroNs(_)
+            | DefPathData::LifetimeNs(_) => {
+                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<Self::Path, Self::Error>,
+        args: &[GenericArg<'tcx>],
+    ) -> Result<Self::Path, Self::Error> {
+        // Don't print any regions if they're all erased.
+        let print_regions = args.iter().any(|arg| match arg.unpack() {
+            GenericArgKind::Lifetime(r) => *r != ty::ReErased,
+            _ => false,
+        });
+        let args = args.iter().cloned().filter(|arg| match arg.unpack() {
+            GenericArgKind::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() {
+                GenericArgKind::Lifetime(lt) => {
+                    self = lt.print(self)?;
+                }
+                GenericArgKind::Type(ty) => {
+                    self = ty.print(self)?;
+                }
+                GenericArgKind::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)
+    }
+}
index d975af52f5bb88007d5a61b4628a8f5d236dbb20..0e6c39e0affca0041d9aebf603afd727b0092b4b 100644 (file)
@@ -1,36 +1,38 @@
 #![feature(rustc_private)]
 
 extern crate rustc;
-extern crate rustc_codegen_utils;
+extern crate rustc_codegen_ssa;
 #[macro_use]
 extern crate rustc_data_structures;
-extern crate rustc_hir;
-extern crate rustc_target;
 extern crate rustc_driver;
+extern crate rustc_hir;
 extern crate rustc_session;
 extern crate rustc_span;
+extern crate rustc_symbol_mangling;
+extern crate rustc_target;
 
-use std::any::Any;
-use std::sync::Arc;
-use std::path::Path;
-use rustc::ty::TyCtxt;
-use rustc::ty::query::Providers;
-use rustc::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
 use rustc::dep_graph::DepGraph;
+use rustc::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
+use rustc::ty::query::Providers;
+use rustc::ty::TyCtxt;
 use rustc::util::common::ErrorReported;
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
-use rustc_data_structures::sync::MetadataRef;
+use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::owning_ref::OwningRef;
-use rustc_session::Session;
+use rustc_data_structures::sync::MetadataRef;
 use rustc_session::config::OutputFilenames;
+use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::Target;
+use std::any::Any;
+use std::path::Path;
+use std::sync::Arc;
 
 pub struct NoLlvmMetadataLoader;
 
 impl MetadataLoader for NoLlvmMetadataLoader {
     fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
-        let buf = std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?;
+        let buf =
+            std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?;
         let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf);
         Ok(rustc_erase_owner!(buf.map_owner_box()))
     }
@@ -48,7 +50,7 @@ fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
     }
 
     fn provide(&self, providers: &mut Providers) {
-        rustc_codegen_utils::symbol_names::provide(providers);
+        rustc_symbol_mangling::provide(providers);
 
         providers.target_features_whitelist = |tcx, _cnum| {
             tcx.arena.alloc(Default::default()) // Just a dummy
@@ -78,7 +80,8 @@ fn join_codegen(
         _sess: &Session,
         _dep_graph: &DepGraph,
     ) -> Result<Box<dyn Any>, ErrorReported> {
-        let crate_name = ongoing_codegen.downcast::<Symbol>()
+        let crate_name = ongoing_codegen
+            .downcast::<Symbol>()
             .expect("in join_codegen: ongoing_codegen is not a Symbol");
         Ok(crate_name)
     }
@@ -89,17 +92,15 @@ fn link(
         codegen_results: Box<dyn Any>,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported> {
+        use rustc_session::{config::CrateType, output::out_filename};
         use std::io::Write;
-        use rustc_session::config::CrateType;
-        use rustc_codegen_utils::link::out_filename;
-        let crate_name = codegen_results.downcast::<Symbol>()
-            .expect("in link: codegen_results is not a Symbol");
+        let crate_name =
+            codegen_results.downcast::<Symbol>().expect("in link: codegen_results is not a Symbol");
         for &crate_type in sess.opts.crate_types.iter() {
             if crate_type != CrateType::Rlib {
                 sess.fatal(&format!("Crate type is {:?}", crate_type));
             }
-            let output_name =
-                out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
+            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
             let mut out_file = ::std::fs::File::create(output_name).unwrap();
             write!(out_file, "This has been \"compiled\" successfully.").unwrap();
         }