"rustc_ast",
"rustc_attr",
"rustc_codegen_ssa",
- "rustc_codegen_utils",
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"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"
"rustc_ast",
"rustc_ast_pretty",
"rustc_codegen_ssa",
- "rustc_codegen_utils",
"rustc_data_structures",
"rustc_error_codes",
"rustc_errors",
"rustc_builtin_macros",
"rustc_codegen_llvm",
"rustc_codegen_ssa",
- "rustc_codegen_utils",
"rustc_data_structures",
"rustc_errors",
"rustc_expand",
"rustc_resolve",
"rustc_session",
"rustc_span",
+ "rustc_symbol_mangling",
"rustc_target",
"rustc_trait_selection",
"rustc_traits",
"rustc",
"rustc_ast",
"rustc_ast_pretty",
- "rustc_codegen_utils",
"rustc_data_structures",
"rustc_hir",
"rustc_parse",
"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"
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,
// 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;
});
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 };
+}
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" }
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};
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" }
rustc_index = { path = "../librustc_index" }
rustc_target = { path = "../librustc_target" }
rustc_session = { path = "../librustc_session" }
+rustc_metadata = { path = "../librustc_metadata" }
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.
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));
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;
// 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,
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};
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};
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);
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 {
{
}
+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>(
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};
+++ /dev/null
-[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" }
+++ /dev/null
-//! 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>;
-}
+++ /dev/null
-//! # 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 };
-}
+++ /dev/null
-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
-}
+++ /dev/null
-//! 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()
-}
+++ /dev/null
-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(())
- }
-}
+++ /dev/null
-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)
- }
-}
+++ /dev/null
-//! 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);
- }
-}
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"] }
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::{
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;
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());
}
}
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" }
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;
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;
// 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);
}
}
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);
}
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;
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)
}
})
})
// 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()?;
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)]
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};
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();
}
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!(
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;
);
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,
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();
- }
-}
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"
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::*;
mod session;
pub use session::*;
+
+pub mod output;
--- /dev/null
+//! 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
+}
--- /dev/null
+[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" }
--- /dev/null
+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(())
+ }
+}
--- /dev/null
+//! 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()
+}
--- /dev/null
+//! 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);
+ }
+}
--- /dev/null
+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)
+ }
+}
#![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()))
}
}
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
_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)
}
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();
}