diff options
Diffstat (limited to 'src/librustc_codegen_utils')
| -rw-r--r-- | src/librustc_codegen_utils/Cargo.toml | 23 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/codegen_backend.rs | 64 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/lib.rs | 66 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/link.rs | 189 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/symbol_names.rs | 262 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/symbol_names/legacy.rs | 434 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/symbol_names/v0.rs | 641 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/symbol_names_test.rs | 70 |
8 files changed, 0 insertions, 1749 deletions
diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml deleted file mode 100644 index b5533a8307c..00000000000 --- a/src/librustc_codegen_utils/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_codegen_utils" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_codegen_utils" -path = "lib.rs" -test = false - -[dependencies] -log = "0.4" -punycode = "0.4.0" -rustc-demangle = "0.1.16" - -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc = { path = "../librustc" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_metadata = { path = "../librustc_metadata" } diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs deleted file mode 100644 index 96166e04c2e..00000000000 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! The Rust compiler. -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] - -use std::any::Any; - -use rustc::dep_graph::DepGraph; -use rustc::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; -use rustc::session::config::{OutputFilenames, PrintRequest}; -use rustc::session::Session; -use rustc::ty::query::Providers; -use rustc::ty::TyCtxt; -use rustc::util::common::ErrorReported; -use rustc_span::symbol::Symbol; - -pub use rustc_data_structures::sync::MetadataRef; - -pub trait CodegenBackend { - fn init(&self, _sess: &Session) {} - fn print(&self, _req: PrintRequest, _sess: &Session) {} - fn target_features(&self, _sess: &Session) -> Vec<Symbol> { - vec![] - } - fn print_passes(&self) {} - fn print_version(&self) {} - - fn metadata_loader(&self) -> Box<MetadataLoaderDyn>; - fn provide(&self, _providers: &mut Providers<'_>); - fn provide_extern(&self, _providers: &mut Providers<'_>); - fn codegen_crate<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - metadata: EncodedMetadata, - need_metadata_module: bool, - ) -> Box<dyn Any>; - - /// This is called on the returned `Box<dyn Any>` from `codegen_backend` - /// - /// # Panics - /// - /// Panics when the passed `Box<dyn Any>` was not returned by `codegen_backend`. - fn join_codegen( - &self, - ongoing_codegen: Box<dyn Any>, - sess: &Session, - dep_graph: &DepGraph, - ) -> Result<Box<dyn Any>, ErrorReported>; - - /// This is called on the returned `Box<dyn Any>` from `join_codegen` - /// - /// # Panics - /// - /// Panics when the passed `Box<dyn Any>` was not returned by `join_codegen`. - fn link( - &self, - sess: &Session, - codegen_results: Box<dyn Any>, - outputs: &OutputFilenames, - ) -> Result<(), ErrorReported>; -} diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs deleted file mode 100644 index 38906bbaef8..00000000000 --- a/src/librustc_codegen_utils/lib.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(never_type)] -#![feature(nll)] -#![feature(in_band_lifetimes)] -#![recursion_limit = "256"] - -#[macro_use] -extern crate rustc; - -use rustc::ty::query::Providers; -use rustc::ty::TyCtxt; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::symbol::sym; - -pub mod codegen_backend; -pub mod link; -pub mod symbol_names; -pub mod symbol_names_test; - -pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: DefId) { - tcx.sess.delay_span_bug( - tcx.def_span(key), - "delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]", - ); -} - -/// check for the #[rustc_error] annotation, which forces an -/// error in codegen. This is used to write compile-fail tests -/// that actually test that compilation succeeds without -/// reporting an error. -pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { - if let Some((def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let attrs = &*tcx.get_attrs(def_id); - for attr in attrs { - if attr.check_name(sym::rustc_error) { - match attr.meta_item_list() { - // check if there is a #[rustc_error(delayed)] - Some(list) => { - if list.iter().any(|list_item| { - list_item.ident().map(|i| i.name) - == Some(sym::delay_span_bug_from_inside_query) - }) { - tcx.ensure().trigger_delay_span_bug(def_id); - } - } - // bare #[rustc_error] - None => { - tcx.sess.span_fatal( - tcx.def_span(def_id), - "fatal error triggered by #[rustc_error]", - ); - } - } - } - } - } -} - -pub fn provide(providers: &mut Providers<'_>) { - crate::symbol_names::provide(providers); - *providers = Providers { trigger_delay_span_bug, ..*providers }; -} diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs deleted file mode 100644 index 524fb0a59c2..00000000000 --- a/src/librustc_codegen_utils/link.rs +++ /dev/null @@ -1,189 +0,0 @@ -use rustc::session::config::{self, Input, OutputFilenames, OutputType}; -use rustc::session::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>| { - 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() && !sess.target.target.options.crt_static_allows_dylibs { - return true; - } - } - _ => {} - } - if sess.target.target.options.only_cdylib { - match crate_type { - config::CrateType::ProcMacro | config::CrateType::Dylib => return true, - _ => {} - } - } - if !sess.target.target.options.executables { - if crate_type == config::CrateType::Executable { - return true; - } - } - - false -} diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs deleted file mode 100644 index 6713459f627..00000000000 --- a/src/librustc_codegen_utils/symbol_names.rs +++ /dev/null @@ -1,262 +0,0 @@ -//! The Rust Linkage Model and Symbol Names -//! ======================================= -//! -//! The semantic model of Rust linkage is, broadly, that "there's no global -//! namespace" between crates. Our aim is to preserve the illusion of this -//! model despite the fact that it's not *quite* possible to implement on -//! modern linkers. We initially didn't use system linkers at all, but have -//! been convinced of their utility. -//! -//! There are a few issues to handle: -//! -//! - Linkers operate on a flat namespace, so we have to flatten names. -//! We do this using the C++ namespace-mangling technique. Foo::bar -//! symbols and such. -//! -//! - Symbols for distinct items with the same *name* need to get different -//! linkage-names. Examples of this are monomorphizations of functions or -//! items within anonymous scopes that end up having the same path. -//! -//! - Symbols in different crates but with same names "within" the crate need -//! to get different linkage-names. -//! -//! - Symbol names should be deterministic: Two consecutive runs of the -//! compiler over the same code base should produce the same symbol names for -//! the same items. -//! -//! - Symbol names should not depend on any global properties of the code base, -//! so that small modifications to the code base do not result in all symbols -//! changing. In previous versions of the compiler, symbol names incorporated -//! the SVH (Stable Version Hash) of the crate. This scheme turned out to be -//! infeasible when used in conjunction with incremental compilation because -//! small code changes would invalidate all symbols generated previously. -//! -//! - Even symbols from different versions of the same crate should be able to -//! live next to each other without conflict. -//! -//! In order to fulfill the above requirements the following scheme is used by -//! the compiler: -//! -//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit -//! hash value into every exported symbol name. Anything that makes a difference -//! to the symbol being named, but does not show up in the regular path needs to -//! be fed into this hash: -//! -//! - Different monomorphizations of the same item have the same path but differ -//! in their concrete type parameters, so these parameters are part of the -//! data being digested for the symbol hash. -//! -//! - Rust allows items to be defined in anonymous scopes, such as in -//! `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have -//! the path `foo::bar`, since the anonymous scopes do not contribute to the -//! path of an item. The compiler already handles this case via so-called -//! disambiguating `DefPaths` which use indices to distinguish items with the -//! same name. The DefPaths of the functions above are thus `foo[0]::bar[0]` -//! and `foo[0]::bar[1]`. In order to incorporate this disambiguation -//! information into the symbol name too, these indices are fed into the -//! symbol hash, so that the above two symbols would end up with different -//! hash values. -//! -//! The two measures described above suffice to avoid intra-crate conflicts. In -//! order to also avoid inter-crate conflicts two more measures are taken: -//! -//! - The name of the crate containing the symbol is prepended to the symbol -//! name, i.e., symbols are "crate qualified". For example, a function `foo` in -//! module `bar` in crate `baz` would get a symbol name like -//! `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids -//! simple conflicts between functions from different crates. -//! -//! - In order to be able to also use symbols from two versions of the same -//! crate (which naturally also have the same name), a stronger measure is -//! required: The compiler accepts an arbitrary "disambiguator" value via the -//! `-C metadata` command-line argument. This disambiguator is then fed into -//! the symbol hash of every exported item. Consequently, the symbols in two -//! identical crates but with different disambiguators are not in conflict -//! with each other. This facility is mainly intended to be used by build -//! tools like Cargo. -//! -//! A note on symbol name stability -//! ------------------------------- -//! Previous versions of the compiler resorted to feeding NodeIds into the -//! symbol hash in order to disambiguate between items with the same path. The -//! current version of the name generation algorithm takes great care not to do -//! that, since NodeIds are notoriously unstable: A small change to the -//! code base will offset all NodeIds after the change and thus, much as using -//! the SVH in the hash, invalidate an unbounded number of symbol names. This -//! makes re-using previously compiled code for incremental compilation -//! virtually impossible. Thus, symbol hash generation exclusively relies on -//! DefPaths which are much more robust in the face of changes to the code base. - -use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc::mir::mono::{InstantiationMode, MonoItem}; -use rustc::session::config::SymbolManglingVersion; -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_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 incorectly. As a result foreign symbols, on the wasm target, - // with a wasm import module, get mangled. Additionally our codegen will - // deduplicate symbols based purely on the symbol name, but for wasm this - // isn't quite right because the same-named symbol on wasm can come from - // different modules. For these reasons if `#[link(wasm_import_module)]` - // is present we mangle everything on wasm because the demangled form will - // show up in the `wasm-import-name` custom attribute in LLVM IR. - // - // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 - if is_foreign { - if tcx.sess.target.target.arch != "wasm32" - || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id) - { - if let Some(name) = attrs.link_name { - return name.to_string(); - } - return tcx.item_name(def_id).to_string(); - } - } - - if let Some(name) = attrs.export_name { - // Use provided name - return name.to_string(); - } - - if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - // Don't mangle - return tcx.item_name(def_id).to_string(); - } - - let avoid_cross_crate_conflicts = - // If this is an instance of a generic function, we also hash in - // the ID of the instantiating crate. This avoids symbol conflicts - // in case the same instances is emitted in two crates of the same - // project. - is_generic(substs) || - - // If we're dealing with an instance of a function that's inlined from - // another crate but we're marking it as globally shared to our - // compliation (aka we're not making an internal copy in each of our - // codegen units) then this symbol may become an exported (but hidden - // visibility) symbol. This means that multiple crates may do the same - // and we want to be sure to avoid any symbol conflicts here. - match MonoItem::Fn(instance).instantiation_mode(tcx) { - InstantiationMode::GloballyShared { may_conflict: true } => true, - _ => false, - }; - - let instantiating_crate = - if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None }; - - // Pick the crate responsible for the symbol mangling version, which has to: - // 1. be stable for each instance, whether it's being defined or imported - // 2. obey each crate's own `-Z symbol-mangling-version`, as much as possible - // We solve these as follows: - // 1. because symbol names depend on both `def_id` and `instantiating_crate`, - // both their `CrateNum`s are stable for any given instance, so we can pick - // either and have a stable choice of symbol mangling version - // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) - let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); - let mangling_version = if mangling_version_crate == LOCAL_CRATE { - tcx.sess.opts.debugging_opts.symbol_mangling_version - } else { - tcx.symbol_mangling_version(mangling_version_crate) - }; - - match mangling_version { - SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), - SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate), - } -} - -fn is_generic(substs: SubstsRef<'_>) -> bool { - substs.non_erasable_generics().next().is_some() -} diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs deleted file mode 100644 index 0dedda9bb6b..00000000000 --- a/src/librustc_codegen_utils/symbol_names/legacy.rs +++ /dev/null @@ -1,434 +0,0 @@ -use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; -use rustc::ich::NodeIdHashingMode; -use rustc::mir::interpret::{ConstValue, Scalar}; -use rustc::ty::print::{PrettyPrinter, Print, Printer}; -use rustc::ty::subst::{GenericArg, GenericArgKind}; -use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; -use rustc::util::common::record_time; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::CrateNum; - -use log::debug; - -use std::fmt::{self, Write}; -use std::mem::{self, discriminant}; - -pub(super) fn mangle( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - instantiating_crate: Option<CrateNum>, -) -> String { - let def_id = instance.def_id(); - - // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. - let mut ty_def_id = def_id; - let instance_ty; - loop { - let key = tcx.def_key(ty_def_id); - match key.disambiguated_data.data { - DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = tcx.type_of(ty_def_id); - break; - } - _ => { - // if we're making a symbol for something, there ought - // to be a value or type-def or something in there - // *somewhere* - ty_def_id.index = key.parent.unwrap_or_else(|| { - bug!( - "finding type for {:?}, encountered def-id {:?} with no \ - parent", - def_id, - ty_def_id - ); - }); - } - } - } - - // Erase regions because they may not be deterministic when hashed - // and should not matter anyhow. - let instance_ty = tcx.erase_regions(&instance_ty); - - let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); - - let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false } - .print_def_path(def_id, &[]) - .unwrap(); - - if instance.is_vtable_shim() { - let _ = printer.write_str("{{vtable-shim}}"); - } - - printer.path.finish(hash) -} - -fn get_symbol_hash<'tcx>( - tcx: TyCtxt<'tcx>, - - // instance this name will be for - instance: Instance<'tcx>, - - // type of the item, without any generic - // parameters substituted; this is - // included in the hash as a kind of - // safeguard. - item_type: Ty<'tcx>, - - instantiating_crate: Option<CrateNum>, -) -> u64 { - let def_id = instance.def_id(); - let substs = instance.substs; - debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); - - let mut hasher = StableHasher::new(); - let mut hcx = tcx.create_stable_hashing_context(); - - record_time(&tcx.sess.perf_stats.symbol_hash_time, || { - // the main symbol name is not necessarily unique; hash in the - // compiler's internal def-path, guaranteeing each symbol has a - // truly unique path - tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); - - // Include the main item-type. Note that, in this case, the - // assertions about `needs_subst` may not hold, but this item-type - // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); - hcx.while_hashing_spans(false, |hcx| { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - item_type.hash_stable(hcx, &mut hasher); - }); - }); - - // If this is a function, we hash the signature as well. - // This is not *strictly* needed, but it may help in some - // situations, see the `run-make/a-b-a-linker-guard` test. - if let ty::FnDef(..) = item_type.kind { - item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher); - } - - // also include any type parameters (for generic items) - assert!(!substs.has_erasable_regions()); - assert!(!substs.needs_subst()); - substs.hash_stable(&mut hcx, &mut hasher); - - if let Some(instantiating_crate) = instantiating_crate { - tcx.original_crate_name(instantiating_crate) - .as_str() - .hash_stable(&mut hcx, &mut hasher); - tcx.crate_disambiguator(instantiating_crate).hash_stable(&mut hcx, &mut hasher); - } - - // We want to avoid accidental collision between different types of instances. - // Especially, VtableShim may overlap with its original instance without this. - discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher); - }); - - // 64 bits should be enough to avoid collisions. - hasher.finish::<u64>() -} - -// Follow C++ namespace-mangling style, see -// http://en.wikipedia.org/wiki/Name_mangling for more info. -// -// It turns out that on macOS you can actually have arbitrary symbols in -// function names (at least when given to LLVM), but this is not possible -// when using unix's linker. Perhaps one day when we just use a linker from LLVM -// we won't need to do this name mangling. The problem with name mangling is -// that it seriously limits the available characters. For example we can't -// have things like &T in symbol names when one would theoretically -// want them for things like impls of traits on that type. -// -// To be able to work on all platforms and get *some* reasonable output, we -// use C++ name-mangling. -#[derive(Debug)] -struct SymbolPath { - result: String, - temp_buf: String, -} - -impl SymbolPath { - fn new() -> Self { - let mut result = - SymbolPath { result: String::with_capacity(64), temp_buf: String::with_capacity(16) }; - result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested - result - } - - fn finalize_pending_component(&mut self) { - if !self.temp_buf.is_empty() { - let _ = write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf); - self.temp_buf.clear(); - } - } - - fn finish(mut self, hash: u64) -> String { - self.finalize_pending_component(); - // E = end name-sequence - let _ = write!(self.result, "17h{:016x}E", hash); - self.result - } -} - -struct SymbolPrinter<'tcx> { - tcx: TyCtxt<'tcx>, - path: SymbolPath, - - // When `true`, `finalize_pending_component` isn't used. - // This is needed when recursing into `path_qualified`, - // or `path_generic_args`, as any nested paths are - // logically within one component. - keep_within_component: bool, -} - -// HACK(eddyb) this relies on using the `fmt` interface to get -// `PrettyPrinter` aka pretty printing of e.g. types in paths, -// symbol names should have their own printing machinery. - -impl Printer<'tcx> for SymbolPrinter<'tcx> { - type Error = fmt::Error; - - type Path = Self; - type Region = Self; - type Type = Self; - type DynExistential = Self; - type Const = Self; - - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { - Ok(self) - } - - fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { - match ty.kind { - // Print all nominal types as paths (unlike `pretty_print_type`). - ty::FnDef(def_id, substs) - | ty::Opaque(def_id, substs) - | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) - | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) - | ty::Closure(def_id, substs) - | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), - _ => self.pretty_print_type(ty), - } - } - - fn print_dyn_existential( - mut self, - predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { - let mut first = true; - for p in predicates { - if !first { - write!(self, "+")?; - } - first = false; - self = p.print(self)?; - } - Ok(self) - } - - fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { - // only print integers - if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { .. })) = ct.val { - if ct.ty.is_integral() { - return self.pretty_print_const(ct, true); - } - } - self.write_str("_")?; - Ok(self) - } - - fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - self.write_str(&self.tcx.original_crate_name(cnum).as_str())?; - Ok(self) - } - fn path_qualified( - self, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - // Similar to `pretty_path_qualified`, but for the other - // types that are printed as paths (see `print_type` above). - match self_ty.kind { - ty::FnDef(..) - | ty::Opaque(..) - | ty::Projection(_) - | ty::UnnormalizedProjection(_) - | ty::Closure(..) - | ty::Generator(..) - if trait_ref.is_none() => - { - self.print_type(self_ty) - } - - _ => self.pretty_path_qualified(self_ty, trait_ref), - } - } - - fn path_append_impl( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - _disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - self.pretty_path_append_impl( - |mut cx| { - cx = print_prefix(cx)?; - - if cx.keep_within_component { - // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it. - cx.write_str("::")?; - } else { - cx.path.finalize_pending_component(); - } - - Ok(cx) - }, - self_ty, - trait_ref, - ) - } - fn path_append( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { - self = print_prefix(self)?; - - // Skip `::{{constructor}}` on tuple/unit structs. - match disambiguated_data.data { - DefPathData::Ctor => return Ok(self), - _ => {} - } - - if self.keep_within_component { - // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it. - self.write_str("::")?; - } else { - self.path.finalize_pending_component(); - } - - self.write_str(&disambiguated_data.data.as_symbol().as_str())?; - Ok(self) - } - fn path_generic_args( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - self = print_prefix(self)?; - - let args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => false, - _ => true, - }); - - if args.clone().next().is_some() { - self.generic_delimiters(|cx| cx.comma_sep(args)) - } else { - Ok(self) - } - } -} - -impl PrettyPrinter<'tcx> for SymbolPrinter<'tcx> { - fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool { - false - } - fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error> - where - T: Print<'tcx, Self, Output = Self, Error = Self::Error>, - { - if let Some(first) = elems.next() { - self = first.print(self)?; - for elem in elems { - self.write_str(",")?; - self = elem.print(self)?; - } - } - Ok(self) - } - - fn generic_delimiters( - mut self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - ) -> Result<Self, Self::Error> { - write!(self, "<")?; - - let kept_within_component = mem::replace(&mut self.keep_within_component, true); - self = f(self)?; - self.keep_within_component = kept_within_component; - - write!(self, ">")?; - - Ok(self) - } -} - -impl fmt::Write for SymbolPrinter<'_> { - fn write_str(&mut self, s: &str) -> fmt::Result { - // Name sanitation. LLVM will happily accept identifiers with weird names, but - // gas doesn't! - // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ - // NVPTX assembly has more strict naming rules than gas, so additionally, dots - // are replaced with '$' there. - - for c in s.chars() { - if self.path.temp_buf.is_empty() { - match c { - 'a'..='z' | 'A'..='Z' | '_' => {} - _ => { - // Underscore-qualify anything that didn't start as an ident. - self.path.temp_buf.push('_'); - } - } - } - match c { - // Escape these with $ sequences - '@' => self.path.temp_buf.push_str("$SP$"), - '*' => self.path.temp_buf.push_str("$BP$"), - '&' => self.path.temp_buf.push_str("$RF$"), - '<' => self.path.temp_buf.push_str("$LT$"), - '>' => self.path.temp_buf.push_str("$GT$"), - '(' => self.path.temp_buf.push_str("$LP$"), - ')' => self.path.temp_buf.push_str("$RP$"), - ',' => self.path.temp_buf.push_str("$C$"), - - '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => { - // NVPTX doesn't support these characters in symbol names. - self.path.temp_buf.push('$') - } - - // '.' doesn't occur in types and functions, so reuse it - // for ':' and '-' - '-' | ':' => self.path.temp_buf.push('.'), - - // Avoid crashing LLVM in certain (LTO-related) situations, see #60925. - 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$u6d$"), - - // These are legal symbols - 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c), - - _ => { - self.path.temp_buf.push('$'); - for c in c.escape_unicode().skip(1) { - match c { - '{' => {} - '}' => self.path.temp_buf.push('$'), - c => self.path.temp_buf.push(c), - } - } - } - } - } - - Ok(()) - } -} diff --git a/src/librustc_codegen_utils/symbol_names/v0.rs b/src/librustc_codegen_utils/symbol_names/v0.rs deleted file mode 100644 index ce6d0d9dc5b..00000000000 --- a/src/librustc_codegen_utils/symbol_names/v0.rs +++ /dev/null @@ -1,641 +0,0 @@ -use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; -use rustc::ty::print::{Print, Printer}; -use rustc::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; -use rustc_ast::ast::{FloatTy, IntTy, UintTy}; -use rustc_data_structures::base_n; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_target::spec::abi::Abi; - -use std::fmt::Write; -use std::ops::Range; - -pub(super) fn mangle( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - instantiating_crate: Option<CrateNum>, -) -> String { - let def_id = instance.def_id(); - // FIXME(eddyb) this should ideally not be needed. - let substs = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs); - - let prefix = "_R"; - let mut cx = SymbolMangler { - tcx, - compress: Some(Box::new(CompressionCaches { - start_offset: prefix.len(), - - paths: FxHashMap::default(), - types: FxHashMap::default(), - consts: FxHashMap::default(), - })), - binders: vec![], - out: String::from(prefix), - }; - cx = if instance.is_vtable_shim() { - cx.path_append_ns(|cx| cx.print_def_path(def_id, substs), 'S', 0, "").unwrap() - } else { - cx.print_def_path(def_id, substs).unwrap() - }; - if let Some(instantiating_crate) = instantiating_crate { - cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap(); - } - cx.out -} - -struct CompressionCaches<'tcx> { - // The length of the prefix in `out` (e.g. 2 for `_R`). - start_offset: usize, - - // The values are start positions in `out`, in bytes. - paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>, - types: FxHashMap<Ty<'tcx>, usize>, - consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>, -} - -struct BinderLevel { - /// The range of distances from the root of what's - /// being printed, to the lifetimes in a binder. - /// Specifically, a `BrAnon(i)` lifetime has depth - /// `lifetime_depths.start + i`, going away from the - /// the root and towards its use site, as `i` increases. - /// This is used to flatten rustc's pairing of `BrAnon` - /// (intra-binder disambiguation) with a `DebruijnIndex` - /// (binder addressing), to "true" de Bruijn indices, - /// by subtracting the depth of a certain lifetime, from - /// the innermost depth at its use site. - lifetime_depths: Range<u32>, -} - -struct SymbolMangler<'tcx> { - tcx: TyCtxt<'tcx>, - compress: Option<Box<CompressionCaches<'tcx>>>, - binders: Vec<BinderLevel>, - out: String, -} - -impl SymbolMangler<'tcx> { - fn push(&mut self, s: &str) { - self.out.push_str(s); - } - - /// Push a `_`-terminated base 62 integer, using the format - /// specified in the RFC as `<base-62-number>`, that is: - /// * `x = 0` is encoded as just the `"_"` terminator - /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`, - /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc. - fn push_integer_62(&mut self, x: u64) { - if let Some(x) = x.checked_sub(1) { - base_n::push_str(x as u128, 62, &mut self.out); - } - self.push("_"); - } - - /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is: - /// * `x = 0` is encoded as `""` (nothing) - /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)` - /// e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc. - fn push_opt_integer_62(&mut self, tag: &str, x: u64) { - if let Some(x) = x.checked_sub(1) { - self.push(tag); - self.push_integer_62(x); - } - } - - fn push_disambiguator(&mut self, dis: u64) { - self.push_opt_integer_62("s", dis); - } - - fn push_ident(&mut self, ident: &str) { - let mut use_punycode = false; - for b in ident.bytes() { - match b { - b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {} - 0x80..=0xff => use_punycode = true, - _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident), - } - } - - let punycode_string; - let ident = if use_punycode { - self.push("u"); - - // FIXME(eddyb) we should probably roll our own punycode implementation. - let mut punycode_bytes = match ::punycode::encode(ident) { - Ok(s) => s.into_bytes(), - Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), - }; - - // Replace `-` with `_`. - if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') { - *c = b'_'; - } - - // FIXME(eddyb) avoid rechecking UTF-8 validity. - punycode_string = String::from_utf8(punycode_bytes).unwrap(); - &punycode_string - } else { - ident - }; - - let _ = write!(self.out, "{}", ident.len()); - - // Write a separating `_` if necessary (leading digit or `_`). - match ident.chars().next() { - Some('_') | Some('0'..='9') => { - self.push("_"); - } - _ => {} - } - - self.push(ident); - } - - fn path_append_ns( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self, !>, - ns: char, - disambiguator: u64, - name: &str, - ) -> Result<Self, !> { - self.push("N"); - self.out.push(ns); - self = print_prefix(self)?; - self.push_disambiguator(disambiguator as u64); - self.push_ident(name); - Ok(self) - } - - fn print_backref(mut self, i: usize) -> Result<Self, !> { - self.push("B"); - self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64); - Ok(self) - } - - fn in_binder<T>( - mut self, - value: &ty::Binder<T>, - print_value: impl FnOnce(Self, &T) -> Result<Self, !>, - ) -> Result<Self, !> - where - T: TypeFoldable<'tcx>, - { - let regions = if value.has_late_bound_regions() { - self.tcx.collect_referenced_late_bound_regions(value) - } else { - FxHashSet::default() - }; - - let mut lifetime_depths = - self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i); - - let lifetimes = regions - .into_iter() - .map(|br| { - match br { - ty::BrAnon(i) => { - // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`. - assert_ne!(i, 0); - i - 1 - } - _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value), - } - }) - .max() - .map_or(0, |max| max + 1); - - self.push_opt_integer_62("G", lifetimes as u64); - lifetime_depths.end += lifetimes; - - self.binders.push(BinderLevel { lifetime_depths }); - self = print_value(self, value.skip_binder())?; - self.binders.pop(); - - Ok(self) - } -} - -impl Printer<'tcx> for SymbolMangler<'tcx> { - type Error = !; - - type Path = Self; - type Region = Self; - type Type = Self; - type DynExistential = Self; - type Const = Self; - - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn print_def_path( - mut self, - def_id: DefId, - substs: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - if let Some(&i) = self.compress.as_ref().and_then(|c| c.paths.get(&(def_id, substs))) { - return self.print_backref(i); - } - let start = self.out.len(); - - self = self.default_print_def_path(def_id, substs)?; - - // Only cache paths that do not refer to an enclosing - // binder (which would change depending on context). - if !substs.iter().any(|k| k.has_escaping_bound_vars()) { - if let Some(c) = &mut self.compress { - c.paths.insert((def_id, substs), start); - } - } - Ok(self) - } - - fn print_impl_path( - self, - impl_def_id: DefId, - substs: &'tcx [GenericArg<'tcx>], - mut self_ty: Ty<'tcx>, - mut impl_trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - let key = self.tcx.def_key(impl_def_id); - let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; - - let mut param_env = self.tcx.param_env(impl_def_id).with_reveal_all(); - if !substs.is_empty() { - param_env = param_env.subst(self.tcx, substs); - } - - match &mut impl_trait_ref { - Some(impl_trait_ref) => { - assert_eq!(impl_trait_ref.self_ty(), self_ty); - *impl_trait_ref = self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref); - self_ty = impl_trait_ref.self_ty(); - } - None => { - self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty); - } - } - - self.path_append_impl( - |cx| cx.print_def_path(parent_def_id, &[]), - &key.disambiguated_data, - self_ty, - impl_trait_ref, - ) - } - - fn print_region(mut self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { - let i = match *region { - // Erased lifetimes use the index 0, for a - // shorter mangling of `L_`. - ty::ReErased => 0, - - // Late-bound lifetimes use indices starting at 1, - // see `BinderLevel` for more details. - ty::ReLateBound(debruijn, ty::BrAnon(i)) => { - // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`. - assert_ne!(i, 0); - let i = i - 1; - - let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; - let depth = binder.lifetime_depths.start + i; - - 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth) - } - - _ => bug!("symbol_names: non-erased region `{:?}`", region), - }; - self.push("L"); - self.push_integer_62(i as u64); - Ok(self) - } - - fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { - // Basic types, never cached (single-character). - let basic_type = match ty.kind { - ty::Bool => "b", - ty::Char => "c", - ty::Str => "e", - ty::Tuple(_) if ty.is_unit() => "u", - ty::Int(IntTy::I8) => "a", - ty::Int(IntTy::I16) => "s", - ty::Int(IntTy::I32) => "l", - ty::Int(IntTy::I64) => "x", - ty::Int(IntTy::I128) => "n", - ty::Int(IntTy::Isize) => "i", - ty::Uint(UintTy::U8) => "h", - ty::Uint(UintTy::U16) => "t", - ty::Uint(UintTy::U32) => "m", - ty::Uint(UintTy::U64) => "y", - ty::Uint(UintTy::U128) => "o", - ty::Uint(UintTy::Usize) => "j", - ty::Float(FloatTy::F32) => "f", - ty::Float(FloatTy::F64) => "d", - ty::Never => "z", - - // Placeholders (should be demangled as `_`). - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => "p", - - _ => "", - }; - if !basic_type.is_empty() { - self.push(basic_type); - return Ok(self); - } - - if let Some(&i) = self.compress.as_ref().and_then(|c| c.types.get(&ty)) { - return self.print_backref(i); - } - let start = self.out.len(); - - match ty.kind { - // Basic types, handled above. - ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never => { - unreachable!() - } - ty::Tuple(_) if ty.is_unit() => unreachable!(), - - // Placeholders, also handled as part of basic types. - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => { - unreachable!() - } - - ty::Ref(r, ty, mutbl) => { - self.push(match mutbl { - hir::Mutability::Not => "R", - hir::Mutability::Mut => "Q", - }); - if *r != ty::ReErased { - self = r.print(self)?; - } - self = ty.print(self)?; - } - - ty::RawPtr(mt) => { - self.push(match mt.mutbl { - hir::Mutability::Not => "P", - hir::Mutability::Mut => "O", - }); - self = mt.ty.print(self)?; - } - - ty::Array(ty, len) => { - self.push("A"); - self = ty.print(self)?; - self = self.print_const(len)?; - } - ty::Slice(ty) => { - self.push("S"); - self = ty.print(self)?; - } - - ty::Tuple(tys) => { - self.push("T"); - for ty in tys.iter().map(|k| k.expect_ty()) { - self = ty.print(self)?; - } - self.push("E"); - } - - // Mangle all nominal types as paths. - ty::Adt(&ty::AdtDef { did: def_id, .. }, substs) - | ty::FnDef(def_id, substs) - | ty::Opaque(def_id, substs) - | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) - | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) - | ty::Closure(def_id, substs) - | ty::Generator(def_id, substs, _) => { - self = self.print_def_path(def_id, substs)?; - } - ty::Foreign(def_id) => { - self = self.print_def_path(def_id, &[])?; - } - - ty::FnPtr(sig) => { - self.push("F"); - self = self.in_binder(&sig, |mut cx, sig| { - if sig.unsafety == hir::Unsafety::Unsafe { - cx.push("U"); - } - match sig.abi { - Abi::Rust => {} - Abi::C => cx.push("KC"), - abi => { - cx.push("K"); - let name = abi.name(); - if name.contains('-') { - cx.push_ident(&name.replace('-', "_")); - } else { - cx.push_ident(name); - } - } - } - for &ty in sig.inputs() { - cx = ty.print(cx)?; - } - if sig.c_variadic { - cx.push("v"); - } - cx.push("E"); - sig.output().print(cx) - })?; - } - - ty::Dynamic(predicates, r) => { - self.push("D"); - self = self.in_binder(&predicates, |cx, predicates| { - cx.print_dyn_existential(predicates) - })?; - self = r.print(self)?; - } - - ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), - } - - // Only cache types that do not refer to an enclosing - // binder (which would change depending on context). - if !ty.has_escaping_bound_vars() { - if let Some(c) = &mut self.compress { - c.types.insert(ty, start); - } - } - Ok(self) - } - - fn print_dyn_existential( - mut self, - predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { - for predicate in predicates { - match *predicate { - ty::ExistentialPredicate::Trait(trait_ref) => { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0)); - let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); - self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; - } - ty::ExistentialPredicate::Projection(projection) => { - let name = self.tcx.associated_item(projection.item_def_id).ident; - self.push("p"); - self.push_ident(&name.as_str()); - self = projection.ty.print(self)?; - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - self = self.print_def_path(def_id, &[])?; - } - } - } - self.push("E"); - Ok(self) - } - - fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { - if let Some(&i) = self.compress.as_ref().and_then(|c| c.consts.get(&ct)) { - return self.print_backref(i); - } - let start = self.out.len(); - - match ct.ty.kind { - ty::Uint(_) => {} - _ => { - bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct); - } - } - self = ct.ty.print(self)?; - - if let Some(bits) = ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty) { - let _ = write!(self.out, "{:x}_", bits); - } else { - // NOTE(eddyb) despite having the path, we need to - // encode a placeholder, as the path could refer - // back to e.g. an `impl` using the constant. - self.push("p"); - } - - // Only cache consts that do not refer to an enclosing - // binder (which would change depending on context). - if !ct.has_escaping_bound_vars() { - if let Some(c) = &mut self.compress { - c.consts.insert(ct, start); - } - } - Ok(self) - } - - fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - self.push("C"); - let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint(); - self.push_disambiguator(fingerprint.to_smaller_hash()); - let name = self.tcx.original_crate_name(cnum).as_str(); - self.push_ident(&name); - Ok(self) - } - fn path_qualified( - mut self, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - assert!(trait_ref.is_some()); - let trait_ref = trait_ref.unwrap(); - - self.push("Y"); - self = self_ty.print(self)?; - self.print_def_path(trait_ref.def_id, trait_ref.substs) - } - - fn path_append_impl( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - self.push(match trait_ref { - Some(_) => "X", - None => "M", - }); - self.push_disambiguator(disambiguated_data.disambiguator as u64); - self = print_prefix(self)?; - self = self_ty.print(self)?; - if let Some(trait_ref) = trait_ref { - self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; - } - Ok(self) - } - fn path_append( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { - let ns = match disambiguated_data.data { - // Uppercase categories are more stable than lowercase ones. - DefPathData::TypeNs(_) => 't', - DefPathData::ValueNs(_) => 'v', - DefPathData::ClosureExpr => 'C', - DefPathData::Ctor => 'c', - DefPathData::AnonConst => 'k', - DefPathData::ImplTrait => 'i', - - // These should never show up as `path_append` arguments. - DefPathData::CrateRoot - | DefPathData::Misc - | DefPathData::Impl - | DefPathData::MacroNs(_) - | DefPathData::LifetimeNs(_) => { - bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) - } - }; - - let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str()); - - self.path_append_ns( - print_prefix, - ns, - disambiguated_data.disambiguator as u64, - name.as_ref().map_or("", |s| &s[..]), - ) - } - fn path_generic_args( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - // Don't print any regions if they're all erased. - let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, - _ => false, - }); - let args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => print_regions, - _ => true, - }); - - if args.clone().next().is_none() { - return print_prefix(self); - } - - self.push("I"); - self = print_prefix(self)?; - for arg in args { - match arg.unpack() { - GenericArgKind::Lifetime(lt) => { - self = lt.print(self)?; - } - GenericArgKind::Type(ty) => { - self = ty.print(self)?; - } - GenericArgKind::Const(c) => { - self.push("K"); - // FIXME(const_generics) implement `ty::print::Print` on `ty::Const`. - // self = c.print(self)?; - self = self.print_const(c)?; - } - } - } - self.push("E"); - - Ok(self) - } -} diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs deleted file mode 100644 index 8f2f2628e7b..00000000000 --- a/src/librustc_codegen_utils/symbol_names_test.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Walks the crate looking for items/impl-items/trait-items that have -//! either a `rustc_symbol_name` or `rustc_def_path` attribute and -//! generates an error giving, respectively, the symbol name or -//! def-path. This is used for unit testing the code that generates -//! paths etc in all kinds of annoying scenarios. - -use rustc::ty::{Instance, TyCtxt}; -use rustc_hir as hir; -use rustc_span::symbol::{sym, Symbol}; - -const SYMBOL_NAME: Symbol = sym::rustc_symbol_name; -const DEF_PATH: Symbol = sym::rustc_def_path; - -pub fn report_symbol_names(tcx: TyCtxt<'_>) { - // if the `rustc_attrs` feature is not enabled, then the - // attributes we are interested in cannot be present anyway, so - // skip the walk. - if !tcx.features().rustc_attrs { - return; - } - - tcx.dep_graph.with_ignore(|| { - let mut visitor = SymbolNamesTest { tcx }; - tcx.hir().krate().visit_all_item_likes(&mut visitor); - }) -} - -struct SymbolNamesTest<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl SymbolNamesTest<'tcx> { - fn process_attrs(&mut self, hir_id: hir::HirId) { - let tcx = self.tcx; - let def_id = tcx.hir().local_def_id(hir_id); - for attr in tcx.get_attrs(def_id).iter() { - if attr.check_name(SYMBOL_NAME) { - // for now, can only use on monomorphic names - let instance = Instance::mono(tcx, def_id); - let mangled = self.tcx.symbol_name(instance); - tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); - if let Ok(demangling) = rustc_demangle::try_demangle(&mangled.name.as_str()) { - tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); - tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); - } - } else if attr.check_name(DEF_PATH) { - let path = tcx.def_path_str(def_id); - tcx.sess.span_err(attr.span, &format!("def-path({})", path)); - } - - // (*) The formatting of `tag({})` is chosen so that tests can elect - // to test the entirety of the string, if they choose, or else just - // some subset. - } - } -} - -impl hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - self.process_attrs(item.hir_id); - } - - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - self.process_attrs(trait_item.hir_id); - } - - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - self.process_attrs(impl_item.hir_id); - } -} |
