diff --git a/mk/tests.mk b/mk/tests.mk index 7f5dbeff1e461..50c060c270a36 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -383,7 +383,7 @@ $(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)): \ @$$(call E, rustc: $$@) $(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(2)) \ $$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) -o $$@ $$< --test \ - -L "$$(RT_OUTPUT_DIR_$(2))" \ + -Cmetadata="test-crate" -L "$$(RT_OUTPUT_DIR_$(2))" \ $$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \ $$(RUSTFLAGS_$(4)) diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index 33ec974c52739..bfcc1759b955d 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -69,10 +69,10 @@ impl fmt::Display for Mode { #[derive(Clone)] pub struct Config { // The library paths required for running the compiler - pub compile_lib_path: String, + pub compile_lib_path: PathBuf, // The library paths required for running compiled programs - pub run_lib_path: String, + pub run_lib_path: PathBuf, // The rustc executable pub rustc_path: PathBuf, diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 96b52eaa0ad0f..6c6a78a360b9e 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -118,9 +118,17 @@ pub fn parse_config(args: Vec ) -> Config { } } + fn make_absolute(path: PathBuf) -> PathBuf { + if path.is_relative() { + env::current_dir().unwrap().join(path) + } else { + path + } + } + Config { - compile_lib_path: matches.opt_str("compile-lib-path").unwrap(), - run_lib_path: matches.opt_str("run-lib-path").unwrap(), + compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), + run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), rustdoc_path: opt_path(matches, "rustdoc-path"), python: matches.opt_str("python").unwrap(), diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 5293eee9459cf..efad2038f82f7 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -316,7 +316,7 @@ fn run_pretty_test_revision(config: &Config, testpaths, pretty_type.to_owned()), props.exec_env.clone(), - &config.compile_lib_path, + config.compile_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), Some(src)) } @@ -635,7 +635,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPa testpaths, proc_args, environment, - &config.run_lib_path, + config.run_lib_path.to_str().unwrap(), None, None); } @@ -1315,7 +1315,7 @@ fn exec_compiled_test(config: &Config, props: &TestProps, testpaths, make_run_args(config, props, testpaths), env, - &config.run_lib_path, + config.run_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), None) } @@ -1387,7 +1387,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, &aux_testpaths, aux_args, Vec::new(), - &config.compile_lib_path, + config.compile_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), None); if !auxres.status.success() { @@ -1410,7 +1410,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, testpaths, args, props.rustc_env.clone(), - &config.compile_lib_path, + config.compile_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), input) } diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 34726a7a6c8ec..ef89b5d25b887 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -166,7 +166,7 @@ impl<'doc> Doc<'doc> { } } - pub fn get<'a>(&'a self, tag: usize) -> Doc<'a> { + pub fn get(&self, tag: usize) -> Doc<'doc> { reader::get_doc(*self, tag) } @@ -174,7 +174,7 @@ impl<'doc> Doc<'doc> { self.start == self.end } - pub fn as_str_slice<'a>(&'a self) -> &'a str { + pub fn as_str_slice(&self) -> &'doc str { str::from_utf8(&self.data[self.start..self.end]).unwrap() } diff --git a/src/librustc/front/map/collector.rs b/src/librustc/front/map/collector.rs index 11aea3727299d..4ae03b1b9d722 100644 --- a/src/librustc/front/map/collector.rs +++ b/src/librustc/front/map/collector.rs @@ -14,7 +14,7 @@ use super::MapEntry::*; use rustc_front::hir::*; use rustc_front::util; use rustc_front::intravisit::{self, Visitor}; -use middle::def_id::{CRATE_DEF_INDEX, DefIndex}; +use middle::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use std::iter::repeat; use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; use syntax::codemap::Span; @@ -50,6 +50,7 @@ impl<'ast> NodeCollector<'ast> { parent: &'ast InlinedParent, parent_node: NodeId, parent_def_path: DefPath, + parent_def_id: DefId, map: Vec>, definitions: Definitions) -> NodeCollector<'ast> { @@ -60,8 +61,14 @@ impl<'ast> NodeCollector<'ast> { definitions: definitions, }; + assert_eq!(parent_def_path.krate, parent_def_id.krate); + let root_path = Box::new(InlinedRootPath { + data: parent_def_path.data, + def_id: parent_def_id, + }); + collector.insert_entry(parent_node, RootInlinedParent(parent)); - collector.create_def(parent_node, DefPathData::InlinedRoot(parent_def_path)); + collector.create_def(parent_node, DefPathData::InlinedRoot(root_path)); collector } @@ -126,11 +133,16 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { // Pick the def data. This need not be unique, but the more // information we encapsulate into let def_data = match i.node { - ItemDefaultImpl(..) | ItemImpl(..) => DefPathData::Impl(i.name), - ItemEnum(..) | ItemStruct(..) | ItemTrait(..) => DefPathData::Type(i.name), - ItemExternCrate(..) | ItemMod(..) => DefPathData::Mod(i.name), - ItemStatic(..) | ItemConst(..) | ItemFn(..) => DefPathData::Value(i.name), - _ => DefPathData::Misc, + ItemDefaultImpl(..) | ItemImpl(..) => + DefPathData::Impl, + ItemEnum(..) | ItemStruct(..) | ItemTrait(..) | + ItemExternCrate(..) | ItemMod(..) | ItemForeignMod(..) | + ItemTy(..) => + DefPathData::TypeNs(i.name), + ItemStatic(..) | ItemConst(..) | ItemFn(..) => + DefPathData::ValueNs(i.name), + ItemUse(..) => + DefPathData::Misc, }; self.insert_def(i.id, NodeItem(i), def_data); @@ -195,7 +207,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { self.insert_def(foreign_item.id, NodeForeignItem(foreign_item), - DefPathData::Value(foreign_item.name)); + DefPathData::ValueNs(foreign_item.name)); let parent_node = self.parent_node; self.parent_node = foreign_item.id; @@ -215,8 +227,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_trait_item(&mut self, ti: &'ast TraitItem) { let def_data = match ti.node { - MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::Value(ti.name), - TypeTraitItem(..) => DefPathData::Type(ti.name), + MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::ValueNs(ti.name), + TypeTraitItem(..) => DefPathData::TypeNs(ti.name), }; self.insert(ti.id, NodeTraitItem(ti)); @@ -239,8 +251,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_impl_item(&mut self, ii: &'ast ImplItem) { let def_data = match ii.node { - ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::Value(ii.name), - ImplItemKind::Type(..) => DefPathData::Type(ii.name), + ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.name), + ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name), }; self.insert_def(ii.id, NodeImplItem(ii), def_data); diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/front/map/definitions.rs index 0f99d85b083fe..82574b852297a 100644 --- a/src/librustc/front/map/definitions.rs +++ b/src/librustc/front/map/definitions.rs @@ -59,23 +59,94 @@ pub struct DefData { pub node_id: ast::NodeId, } -pub type DefPath = Vec; +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct DefPath { + /// the path leading from the crate root to the item + pub data: Vec, + + /// what krate root is this path relative to? + pub krate: ast::CrateNum, +} + +impl DefPath { + pub fn is_local(&self) -> bool { + self.krate == LOCAL_CRATE + } + + pub fn make(start_krate: ast::CrateNum, + start_index: DefIndex, + mut get_key: FN) -> DefPath + where FN: FnMut(DefIndex) -> DefKey + { + let mut krate = start_krate; + let mut data = vec![]; + let mut index = Some(start_index); + loop { + let p = index.unwrap(); + let key = get_key(p); + match key.disambiguated_data.data { + DefPathData::CrateRoot => { + assert!(key.parent.is_none()); + break; + } + DefPathData::InlinedRoot(ref p) => { + assert!(key.parent.is_none()); + assert!(!p.def_id.is_local()); + data.extend(p.data.iter().cloned().rev()); + krate = p.def_id.krate; + break; + } + _ => { + data.push(key.disambiguated_data); + index = key.parent; + } + } + } + data.reverse(); + DefPath { data: data, krate: krate } + } +} + +/// Root of an inlined item. We track the `DefPath` of the item within +/// the original crate but also its def-id. This is kind of an +/// augmented version of a `DefPath` that includes a `DefId`. This is +/// all sort of ugly but the hope is that inlined items will be going +/// away soon anyway. +/// +/// Some of the constraints that led to the current approach: +/// +/// - I don't want to have a `DefId` in the main `DefPath` because +/// that gets serialized for incr. comp., and when reloaded the +/// `DefId` is no longer valid. I'd rather maintain the invariant +/// that every `DefId` is valid, and a potentially outdated `DefId` is +/// represented as a `DefPath`. +/// - (We don't serialize def-paths from inlined items, so it's ok to have one here.) +/// - We need to be able to extract the def-id from inline items to +/// make the symbol name. In theory we could retrace it from the +/// data, but the metadata doesn't have the required indices, and I +/// don't want to write the code to create one just for this. +/// - It may be that we don't actually need `data` at all. We'll have +/// to see about that. +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct InlinedRootPath { + pub data: Vec, + pub def_id: DefId, +} #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum DefPathData { // Root: these should only be used for the root nodes, because // they are treated specially by the `def_path` function. CrateRoot, - InlinedRoot(DefPath), + InlinedRoot(Box), // Catch-all for random DefId things like DUMMY_NODE_ID Misc, // Different kinds of items and item-like things: - Impl(ast::Name), - Type(ast::Name), - Mod(ast::Name), - Value(ast::Name), + Impl, + TypeNs(ast::Name), // something in the type NS + ValueNs(ast::Name), // something in the value NS MacroDef(ast::Name), ClosureExpr, @@ -87,10 +158,6 @@ pub enum DefPathData { StructCtor, // implicit ctor for a tuple-like struct Initializer, // initializer for a const Binding(ast::Name), // pattern binding - - // An external crate that does not have an `extern crate` in this - // crate. - DetachedCrate(ast::Name), } impl Definitions { @@ -116,7 +183,7 @@ impl Definitions { /// will be the path of the item in the external crate (but the /// path will begin with the path to the external crate). pub fn def_path(&self, index: DefIndex) -> DefPath { - make_def_path(index, |p| self.def_key(p)) + DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p)) } pub fn opt_def_index(&self, node: ast::NodeId) -> Option { @@ -175,20 +242,21 @@ impl DefPathData { pub fn as_interned_str(&self) -> InternedString { use self::DefPathData::*; match *self { - Impl(name) | - Type(name) | - Mod(name) | - Value(name) | + TypeNs(name) | + ValueNs(name) | MacroDef(name) | TypeParam(name) | LifetimeDef(name) | EnumVariant(name) | - DetachedCrate(name) | Binding(name) | Field(name) => { name.as_str() } + Impl => { + InternedString::new("{{impl}}") + } + // note that this does not show up in user printouts CrateRoot => { InternedString::new("{{root}}") @@ -222,29 +290,3 @@ impl DefPathData { } } -pub fn make_def_path(start_index: DefIndex, mut get_key: FN) -> DefPath - where FN: FnMut(DefIndex) -> DefKey -{ - let mut result = vec![]; - let mut index = Some(start_index); - while let Some(p) = index { - let key = get_key(p); - match key.disambiguated_data.data { - DefPathData::CrateRoot => { - assert!(key.parent.is_none()); - break; - } - DefPathData::InlinedRoot(ref p) => { - assert!(key.parent.is_none()); - result.extend(p.iter().cloned().rev()); - break; - } - _ => { - result.push(key.disambiguated_data); - index = key.parent; - } - } - } - result.reverse(); - result -} diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs index dfc8560b58de0..6d6f20c70ec4d 100644 --- a/src/librustc/front/map/mod.rs +++ b/src/librustc/front/map/mod.rs @@ -12,13 +12,14 @@ pub use self::Node::*; pub use self::PathElem::*; use self::MapEntry::*; use self::collector::NodeCollector; -pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; +pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, + DisambiguatedDefPathData, InlinedRootPath}; use dep_graph::{DepGraph, DepNode}; use middle::cstore::InlinedItem; use middle::cstore::InlinedItem as II; -use middle::def_id::DefId; +use middle::def_id::{CRATE_DEF_INDEX, DefId}; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID}; @@ -322,7 +323,8 @@ impl<'ast> Map<'ast> { id = p, RootCrate | - RootInlinedParent(_) => // FIXME(#2369) clarify story about cross-crate dep tracking + RootInlinedParent(_) => + // FIXME(#32015) clarify story about cross-crate dep tracking return DepNode::Krate, NotPresent => @@ -386,6 +388,15 @@ impl<'ast> Map<'ast> { self.forest.krate() } + /// Get the attributes on the krate. This is preferable to + /// invoking `krate.attrs` because it registers a tighter + /// dep-graph access. + pub fn krate_attrs(&self) -> &'ast [ast::Attribute] { + let crate_root_def_id = DefId::local(CRATE_DEF_INDEX); + self.dep_graph.read(DepNode::Hir(crate_root_def_id)); + &self.forest.krate.attrs + } + /// Retrieve the Node corresponding to `id`, panicking if it cannot /// be found. pub fn get(&self, id: NodeId) -> Node<'ast> { @@ -958,6 +969,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, parent_path: Vec, parent_def_path: DefPath, + parent_def_id: DefId, ii: InlinedItem, fold_ops: F) -> &'ast InlinedItem { @@ -987,6 +999,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, ii_parent, ii_parent_id, parent_def_path, + parent_def_id, mem::replace(&mut *map.map.borrow_mut(), vec![]), mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new())); ii_parent.ii.visit(&mut collector); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index f85d87413843e..7cad9b10f85ec 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -42,6 +42,7 @@ use syntax::ast_util::{IdVisitingOperation}; use syntax::attr; use syntax::codemap::Span; use syntax::ptr::P; +use syntax::parse::token::InternedString; use rustc_back::target::Target; use rustc_front::hir; use rustc_front::intravisit::Visitor; @@ -126,6 +127,27 @@ pub enum FoundAst<'ast> { NotFound, } +#[derive(Copy, Clone, Debug)] +pub struct ExternCrate { + /// def_id of an `extern crate` in the current crate that caused + /// this crate to be loaded; note that there could be multiple + /// such ids + pub def_id: DefId, + + /// span of the extern crate that caused this to be loaded + pub span: Span, + + /// If true, then this crate is the crate named by the extern + /// crate referenced above. If false, then this crate is a dep + /// of the crate. + pub direct: bool, + + /// Number of links to reach the extern crate `def_id` + /// declaration; used to select the extern crate with the shortest + /// path + pub path_len: usize, +} + /// A store of Rust crates, through with their metadata /// can be accessed. /// @@ -146,7 +168,7 @@ pub trait CrateStore<'tcx> : Any { fn repr_attrs(&self, def: DefId) -> Vec; fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::TypeScheme<'tcx>; - fn item_path(&self, def: DefId) -> Vec; + fn relative_item_path(&self, def: DefId) -> Vec; fn extern_item_path(&self, def: DefId) -> Vec; fn item_name(&self, def: DefId) -> ast::Name; fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId) @@ -202,9 +224,15 @@ pub trait CrateStore<'tcx> : Any { fn is_staged_api(&self, cnum: ast::CrateNum) -> bool; fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; fn is_allocator(&self, cnum: ast::CrateNum) -> bool; + fn extern_crate(&self, cnum: ast::CrateNum) -> Option; fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; - fn crate_name(&self, cnum: ast::CrateNum) -> String; + /// The name of the crate as it is referred to in source code of the current + /// crate. + fn crate_name(&self, cnum: ast::CrateNum) -> InternedString; + /// The name of the crate as it is stored in the crate's metadata. + fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString; fn crate_hash(&self, cnum: ast::CrateNum) -> Svh; + fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString; fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) -> FnvHashMap>; fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option; @@ -212,7 +240,8 @@ pub trait CrateStore<'tcx> : Any { fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec; // resolve - fn def_path(&self, def: DefId) -> hir_map::DefPath; + fn def_key(&self, def: DefId) -> hir_map::DefKey; + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath; fn variant_kind(&self, def_id: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; @@ -236,7 +265,11 @@ pub trait CrateStore<'tcx> : Any { // utility functions fn metadata_filename(&self) -> &str; fn metadata_section_name(&self, target: &Target) -> &str; - fn encode_type(&self, tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec; + fn encode_type(&self, + tcx: &TyCtxt<'tcx>, + ty: Ty<'tcx>, + def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String) + -> Vec; fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)>; fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource; fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; @@ -313,7 +346,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn repr_attrs(&self, def: DefId) -> Vec { unimplemented!() } fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::TypeScheme<'tcx> { unimplemented!() } - fn item_path(&self, def: DefId) -> Vec { unimplemented!() } + fn relative_item_path(&self, def: DefId) -> Vec { unimplemented!() } fn extern_item_path(&self, def: DefId) -> Vec { unimplemented!() } fn item_name(&self, def: DefId) -> ast::Name { unimplemented!() } fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId) @@ -376,10 +409,15 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } fn is_allocator(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } + fn extern_crate(&self, cnum: ast::CrateNum) -> Option { unimplemented!() } fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec { unimplemented!() } - fn crate_name(&self, cnum: ast::CrateNum) -> String { unimplemented!() } + fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() } + fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString { + unimplemented!() + } fn crate_hash(&self, cnum: ast::CrateNum) -> Svh { unimplemented!() } + fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() } fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) -> FnvHashMap> { unimplemented!() } @@ -390,7 +428,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec { unimplemented!() } // resolve - fn def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() } + fn def_key(&self, def: DefId) -> hir_map::DefKey { unimplemented!() } + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() } fn variant_kind(&self, def_id: DefId) -> Option { unimplemented!() } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { unimplemented!() } @@ -419,8 +458,13 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // utility functions fn metadata_filename(&self) -> &str { unimplemented!() } fn metadata_section_name(&self, target: &Target) -> &str { unimplemented!() } - fn encode_type(&self, tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec - { unimplemented!() } + fn encode_type(&self, + tcx: &TyCtxt<'tcx>, + ty: Ty<'tcx>, + def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String) + -> Vec { + unimplemented!() + } fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)> { vec![] } fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource { unimplemented!() } diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 937196b5e8e7a..b2ba8a7a5f99f 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -398,7 +398,7 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, // purposes of the ancestor check, we retain // the invariant that all type variables are // fully refreshed. - if !(&mut is_ancestor)(&obligation.predicate) { + if !is_ancestor(&obligation.predicate) { return None; } } diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 03c13115aea62..6acd094c1f90d 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -15,7 +15,7 @@ use front::map as ast_map; use session::Session; use lint; use middle; -use middle::cstore::CrateStore; +use middle::cstore::{CrateStore, LOCAL_CRATE}; use middle::def::DefMap; use middle::def_id::DefId; use middle::free_region::FreeRegionMap; @@ -43,7 +43,7 @@ use std::hash::{Hash, Hasher}; use std::rc::Rc; use syntax::ast::{self, Name, NodeId}; use syntax::attr; -use syntax::parse::token::special_idents; +use syntax::parse::token::{self, special_idents}; use rustc_front::hir; @@ -415,9 +415,29 @@ pub struct TyCtxt<'tcx> { /// fragmented data to the set of unfragmented pieces that /// constitute it. pub fragment_infos: RefCell>>, + + /// The definite name of the current crate after taking into account + /// attributes, commandline parameters, etc. + pub crate_name: token::InternedString, } impl<'tcx> TyCtxt<'tcx> { + pub fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString { + if cnum == LOCAL_CRATE { + self.crate_name.clone() + } else { + self.sess.cstore.crate_name(cnum) + } + } + + pub fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString { + if cnum == LOCAL_CRATE { + self.sess.crate_disambiguator.get().as_str() + } else { + self.sess.cstore.crate_name(cnum) + } + } + pub fn type_parameter_def(&self, node_id: NodeId) -> ty::TypeParameterDef<'tcx> @@ -511,6 +531,7 @@ impl<'tcx> TyCtxt<'tcx> { region_maps: RegionMaps, lang_items: middle::lang_items::LanguageItems, stability: stability::Index<'tcx>, + crate_name: &str, f: F) -> R where F: FnOnce(&TyCtxt<'tcx>) -> R { @@ -570,7 +591,8 @@ impl<'tcx> TyCtxt<'tcx> { const_qualif_map: RefCell::new(NodeMap()), custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), cast_kinds: RefCell::new(NodeMap()), - fragment_infos: RefCell::new(DefIdMap()) + fragment_infos: RefCell::new(DefIdMap()), + crate_name: token::intern_and_get_ident(crate_name), }, f) } } diff --git a/src/librustc/middle/ty/item_path.rs b/src/librustc/middle/ty/item_path.rs new file mode 100644 index 0000000000000..147230f5bdcd0 --- /dev/null +++ b/src/librustc/middle/ty/item_path.rs @@ -0,0 +1,317 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use front::map::DefPathData; +use middle::cstore::LOCAL_CRATE; +use middle::def_id::DefId; +use middle::ty::{self, Ty, TyCtxt}; +use syntax::ast; + +impl<'tcx> TyCtxt<'tcx> { + /// Returns a string identifying this def-id. This string is + /// suitable for user output. It is relative to the current crate + /// root. + pub fn item_path_str(&self, def_id: DefId) -> String { + let mut buffer = LocalPathBuffer::new(RootMode::Local); + self.push_item_path(&mut buffer, def_id); + buffer.into_string() + } + + /// Returns a string identifying this def-id. This string is + /// suitable for user output. It always begins with a crate identifier. + pub fn absolute_item_path_str(&self, def_id: DefId) -> String { + let mut buffer = LocalPathBuffer::new(RootMode::Absolute); + self.push_item_path(&mut buffer, def_id); + buffer.into_string() + } + + /// Returns the "path" to a particular crate. This can proceed in + /// various ways, depending on the `root_mode` of the `buffer`. + /// (See `RootMode` enum for more details.) + pub fn push_krate_path(&self, buffer: &mut T, cnum: ast::CrateNum) + where T: ItemPathBuffer + { + match *buffer.root_mode() { + RootMode::Local => { + // In local mode, when we encounter a crate other than + // LOCAL_CRATE, execution proceeds in one of two ways: + // + // 1. for a direct dependency, where user added an + // `extern crate` manually, we put the `extern + // crate` as the parent. So you wind up with + // something relative to the current crate. + // 2. for an indirect crate, where there is no extern + // crate, we just prepend the crate name. + // + // Returns `None` for the local crate. + if cnum != LOCAL_CRATE { + let opt_extern_crate = self.sess.cstore.extern_crate(cnum); + let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| { + if extern_crate.direct { + Some(extern_crate.def_id) + } else { + None + } + }); + if let Some(extern_crate_def_id) = opt_extern_crate { + self.push_item_path(buffer, extern_crate_def_id); + } else { + buffer.push(&self.crate_name(cnum)); + } + } + } + RootMode::Absolute => { + // In absolute mode, just write the crate name + // unconditionally. + buffer.push(&self.crate_name(cnum)); + } + } + } + + pub fn push_item_path(&self, buffer: &mut T, def_id: DefId) + where T: ItemPathBuffer + { + let key = self.def_key(def_id); + match key.disambiguated_data.data { + DefPathData::CrateRoot => { + assert!(key.parent.is_none()); + self.push_krate_path(buffer, def_id.krate); + } + + DefPathData::InlinedRoot(ref root_path) => { + assert!(key.parent.is_none()); + self.push_item_path(buffer, root_path.def_id); + } + + DefPathData::Impl => { + self.push_impl_path(buffer, def_id); + } + + // Unclear if there is any value in distinguishing these. + // Probably eventually (and maybe we would even want + // finer-grained distinctions, e.g. between enum/struct). + data @ DefPathData::Misc | + data @ DefPathData::TypeNs(..) | + data @ DefPathData::ValueNs(..) | + data @ DefPathData::TypeParam(..) | + data @ DefPathData::LifetimeDef(..) | + data @ DefPathData::EnumVariant(..) | + data @ DefPathData::Field(..) | + data @ DefPathData::StructCtor | + data @ DefPathData::Initializer | + data @ DefPathData::MacroDef(..) | + data @ DefPathData::ClosureExpr | + data @ DefPathData::Binding(..) => { + let parent_def_id = self.parent_def_id(def_id).unwrap(); + self.push_item_path(buffer, parent_def_id); + buffer.push(&data.as_interned_str()); + } + } + } + + fn push_impl_path(&self, + buffer: &mut T, + impl_def_id: DefId) + where T: ItemPathBuffer + { + let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); + + let use_types = if !impl_def_id.is_local() { + // always have full types available for extern crates + true + } else { + // for local crates, check whether type info is + // available; typeck might not have completed yet + self.impl_trait_refs.borrow().contains_key(&impl_def_id) + }; + + if !use_types { + return self.push_impl_path_fallback(buffer, impl_def_id); + } + + // Decide whether to print the parent path for the impl. + // Logically, since impls are global, it's never needed, but + // users may find it useful. Currently, we omit the parent if + // the impl is either in the same module as the self-type or + // as the trait. + let self_ty = self.lookup_item_type(impl_def_id).ty; + let in_self_mod = match self.characteristic_def_id_of_type(self_ty) { + None => false, + Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), + }; + + let impl_trait_ref = self.impl_trait_ref(impl_def_id); + let in_trait_mod = match impl_trait_ref { + None => false, + Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id), + }; + + if !in_self_mod && !in_trait_mod { + // If the impl is not co-located with either self-type or + // trait-type, then fallback to a format that identifies + // the module more clearly. + self.push_item_path(buffer, parent_def_id); + if let Some(trait_ref) = impl_trait_ref { + buffer.push(&format!("", trait_ref, self_ty)); + } else { + buffer.push(&format!("", self_ty)); + } + return; + } + + // Otherwise, try to give a good form that would be valid language + // syntax. Preferably using associated item notation. + + if let Some(trait_ref) = impl_trait_ref { + // Trait impls. + buffer.push(&format!("<{} as {}>", + self_ty, + trait_ref)); + return; + } + + // Inherent impls. Try to print `Foo::bar` for an inherent + // impl on `Foo`, but fallback to `::bar` if self-type is + // anything other than a simple path. + match self_ty.sty { + ty::TyStruct(adt_def, substs) | + ty::TyEnum(adt_def, substs) => { + if substs.types.is_empty() { // ignore regions + self.push_item_path(buffer, adt_def.did); + } else { + buffer.push(&format!("<{}>", self_ty)); + } + } + + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyStr => { + buffer.push(&format!("{}", self_ty)); + } + + _ => { + buffer.push(&format!("<{}>", self_ty)); + } + } + } + + fn push_impl_path_fallback(&self, + buffer: &mut T, + impl_def_id: DefId) + where T: ItemPathBuffer + { + // If no type info is available, fall back to + // pretty printing some span information. This should + // only occur very early in the compiler pipeline. + let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); + self.push_item_path(buffer, parent_def_id); + let node_id = self.map.as_local_node_id(impl_def_id).unwrap(); + let item = self.map.expect_item(node_id); + let span_str = self.sess.codemap().span_to_string(item.span); + buffer.push(&format!("", span_str)); + } + + /// As a heuristic, when we see an impl, if we see that the + /// 'self-type' is a type defined in the same module as the impl, + /// we can omit including the path to the impl itself. This + /// function tries to find a "characteristic def-id" for a + /// type. It's just a heuristic so it makes some questionable + /// decisions and we may want to adjust it later. + fn characteristic_def_id_of_type(&self, ty: Ty<'tcx>) -> Option { + match ty.sty { + ty::TyStruct(adt_def, _) | + ty::TyEnum(adt_def, _) => + Some(adt_def.did), + + ty::TyTrait(ref data) => + Some(data.principal_def_id()), + + ty::TyBox(subty) => + self.characteristic_def_id_of_type(subty), + + ty::TyRawPtr(mt) | + ty::TyRef(_, mt) => + self.characteristic_def_id_of_type(mt.ty), + + ty::TyTuple(ref tys) => + tys.iter() + .filter_map(|ty| self.characteristic_def_id_of_type(ty)) + .next(), + + _ => + None + } + } + + /// Returns the def-id of `def_id`'s parent in the def tree. If + /// this returns `None`, then `def_id` represents a crate root or + /// inlined root. + fn parent_def_id(&self, def_id: DefId) -> Option { + let key = self.def_key(def_id); + key.parent.map(|index| DefId { krate: def_id.krate, index: index }) + } +} + +/// Unifying Trait for different kinds of item paths we might +/// construct. The basic interface is that components get pushed: the +/// instance can also customize how we handle the root of a crate. +pub trait ItemPathBuffer { + fn root_mode(&self) -> &RootMode; + fn push(&mut self, text: &str); +} + +#[derive(Debug)] +pub enum RootMode { + /// Try to make a path relative to the local crate. In + /// particular, local paths have no prefix, and if the path comes + /// from an extern crate, start with the path to the `extern + /// crate` declaration. + Local, + + /// Always prepend the crate name to the path, forming an absolute + /// path from within a given set of crates. + Absolute, +} + +#[derive(Debug)] +struct LocalPathBuffer { + root_mode: RootMode, + str: String, +} + +impl LocalPathBuffer { + fn new(root_mode: RootMode) -> LocalPathBuffer { + LocalPathBuffer { + root_mode: root_mode, + str: String::new() + } + } + + fn into_string(self) -> String { + self.str + } + +} + +impl ItemPathBuffer for LocalPathBuffer { + fn root_mode(&self) -> &RootMode { + &self.root_mode + } + + fn push(&mut self, text: &str) { + if !self.str.is_empty() { + self.str.push_str("::"); + } + self.str.push_str(text); + } +} diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 050024d0e94ea..a4c3e82b6335d 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -86,6 +86,7 @@ pub mod cast; pub mod error; pub mod fast_reject; pub mod fold; +pub mod item_path; pub mod _match; pub mod maps; pub mod outlives; @@ -2218,15 +2219,22 @@ impl<'tcx> TyCtxt<'tcx> { self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id() } - pub fn item_path_str(&self, id: DefId) -> String { - self.with_path(id, |path| ast_map::path_to_string(path)) + pub fn def_key(&self, id: DefId) -> ast_map::DefKey { + if id.is_local() { + self.map.def_key(id) + } else { + self.sess.cstore.def_key(id) + } } + /// Returns the `DefPath` of an item. Note that if `id` is not + /// local to this crate -- or is inlined into this crate -- the + /// result will be a non-local `DefPath`. pub fn def_path(&self, id: DefId) -> ast_map::DefPath { if id.is_local() { self.map.def_path(id) } else { - self.sess.cstore.def_path(id) + self.sess.cstore.relative_def_path(id) } } @@ -2236,7 +2244,27 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = self.map.as_local_node_id(id) { self.map.with_path(id, f) } else { - f(self.sess.cstore.item_path(id).iter().cloned().chain(LinkedPath::empty())) + let mut path: Vec<_>; + if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) { + if !extern_crate.direct { + // this comes from some crate that we don't have a direct + // path to; we'll settle for just prepending the name of + // the crate. + path = self.sess.cstore.extern_item_path(id) + } else { + // start with the path to the extern crate, then + // add the relative path to the actual item + fn collector(elems: ast_map::PathElems) -> Vec { + elems.collect() + } + path = self.with_path(extern_crate.def_id, collector); + path.extend(self.sess.cstore.relative_item_path(id)); + } + } else { + // if this was injected, just make a path with name of crate + path = self.sess.cstore.extern_item_path(id); + } + f(path.iter().cloned().chain(LinkedPath::empty())) } } @@ -2680,9 +2708,10 @@ impl<'tcx> TyCtxt<'tcx> { { dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor); } + /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` /// with the name of the crate containing the impl. - pub fn span_of_impl(&self, impl_did: DefId) -> Result { + pub fn span_of_impl(&self, impl_did: DefId) -> Result { if impl_did.is_local() { let node_id = self.map.as_local_node_id(impl_did).unwrap(); Ok(self.map.span(node_id)) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index b198eda181208..3e6878408681c 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -24,6 +24,7 @@ use syntax::diagnostics; use syntax::feature_gate; use syntax::parse; use syntax::parse::ParseSess; +use syntax::parse::token; use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; @@ -64,7 +65,12 @@ pub struct Session { pub plugin_attributes: RefCell>, pub crate_types: RefCell>, pub dependency_formats: RefCell, - pub crate_metadata: RefCell>, + // The crate_disambiguator is constructed out of all the `-C metadata` + // arguments passed to the compiler. Its value together with the crate-name + // forms a unique global identifier for the crate. It is used to allow + // multiple crates with the same name to coexist. See the + // trans::back::symbol_names module for more information. + pub crate_disambiguator: Cell, pub features: RefCell, /// The maximum recursion limit for potentially infinitely recursive @@ -481,7 +487,7 @@ pub fn build_session_(sopts: config::Options, plugin_attributes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FnvHashMap()), - crate_metadata: RefCell::new(Vec::new()), + crate_disambiguator: Cell::new(token::intern("")), features: RefCell::new(feature_gate::Features::new()), recursion_limit: Cell::new(64), next_node_id: Cell::new(1), diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 3507a119e5455..ec607314f45c0 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -66,7 +66,7 @@ impl Svh { &self.hash } - pub fn calculate(metadata: &Vec, krate: &hir::Crate) -> Svh { + pub fn calculate(crate_disambiguator: &str, krate: &hir::Crate) -> Svh { // FIXME (#14132): This is better than it used to be, but it still not // ideal. We now attempt to hash only the relevant portions of the // Crate AST as well as the top-level crate attributes. (However, @@ -78,9 +78,9 @@ impl Svh { // avoid collisions. let mut state = SipHasher::new(); - for data in metadata { - data.hash(&mut state); - } + "crate_disambiguator".hash(&mut state); + crate_disambiguator.len().hash(&mut state); + crate_disambiguator.hash(&mut state); { let mut visit = svh_visitor::make(&mut state, krate); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 55b873c06630a..96e819ea91fee 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -22,6 +22,7 @@ use rustc::middle::privacy::AccessLevels; use rustc::middle::ty::TyCtxt; use rustc::util::common::time; use rustc::util::nodemap::NodeSet; +use rustc_back::sha2::{Sha256, Digest}; use rustc_borrowck as borrowck; use rustc_resolve as resolve; use rustc_metadata::macro_import; @@ -500,7 +501,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, })?; *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); - *sess.crate_metadata.borrow_mut() = collect_crate_metadata(sess, &krate.attrs); + sess.crate_disambiguator.set(token::intern(&compute_crate_disambiguator(sess))); time(time_passes, "recursion limit", || { middle::recursion_limit::update_recursion_limit(sess, &krate); @@ -525,11 +526,15 @@ pub fn phase_2_configure_and_expand(sess: &Session, let macros = time(time_passes, "macro loading", - || macro_import::read_macro_defs(sess, &cstore, &krate)); + || macro_import::read_macro_defs(sess, &cstore, &krate, crate_name)); let mut addl_plugins = Some(addl_plugins); let registrars = time(time_passes, "plugin loading", || { - plugin::load::load_plugins(sess, &cstore, &krate, addl_plugins.take().unwrap()) + plugin::load::load_plugins(sess, + &cstore, + &krate, + crate_name, + addl_plugins.take().unwrap()) }); let mut registry = Registry::new(sess, &krate); @@ -754,7 +759,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "external crate/lib resolution", - || LocalCrateReader::new(sess, cstore, &hir_map).read_crates()); + || LocalCrateReader::new(sess, cstore, &hir_map, name).read_crates()); let lang_items = time(time_passes, "language item collection", || { sess.track_errors(|| { @@ -817,6 +822,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, region_map, lang_items, index, + name, |tcx| { // passes are timed inside typeck try_with_f!(typeck::check_crate(tcx, trait_map), (tcx, None, analysis)); @@ -1121,8 +1127,34 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec Vec { - session.opts.cg.metadata.clone() +pub fn compute_crate_disambiguator(session: &Session) -> String { + let mut hasher = Sha256::new(); + + let mut metadata = session.opts.cg.metadata.clone(); + // We don't want the crate_disambiguator to dependent on the order + // -C metadata arguments, so sort them: + metadata.sort(); + // Every distinct -C metadata value is only incorporated once: + metadata.dedup(); + + hasher.input_str("metadata"); + for s in &metadata { + // Also incorporate the length of a metadata string, so that we generate + // different values for `-Cmetadata=ab -Cmetadata=c` and + // `-Cmetadata=a -Cmetadata=bc` + hasher.input_str(&format!("{}", s.len())[..]); + hasher.input_str(&s[..]); + } + + let mut hash = hasher.result_str(); + + // If this is an executable, add a special suffix, so that we don't get + // symbol conflicts when linking against a library of the same name. + if session.crate_types.borrow().contains(&config::CrateTypeExecutable) { + hash.push_str("-exe"); + } + + hash } pub fn build_output_filenames(input: &Input, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index dc30b4f91a985..9ba6abb962ead 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -568,8 +568,6 @@ impl RustcDefaultCalls { continue; } let crate_types = driver::collect_crate_types(sess, attrs); - let metadata = driver::collect_crate_metadata(sess, attrs); - *sess.crate_metadata.borrow_mut() = metadata; for &style in &crate_types { let fname = link::filename_for_input(sess, style, &id, &t_outputs); println!("{}", diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 1a5e7cb54f2e3..111db3b1d3890 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -146,6 +146,7 @@ fn test_env(source_string: &str, region_map, lang_items, index, + "test_crate", |tcx| { let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 5c5574c3a8300..60f7110764699 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -125,6 +125,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, tcx: &TyCtxt<'tcx>, parent_path: Vec, parent_def_path: ast_map::DefPath, + parent_did: DefId, ast_doc: rbml::Doc, orig_did: DefId) -> &'tcx InlinedItem { @@ -149,6 +150,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, let ii = ast_map::map_decoded_item(&dcx.tcx.map, parent_path, parent_def_path, + parent_did, decode_ast(ast_doc), dcx); let name = match *ii { @@ -349,8 +351,8 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem { } } -fn decode_ast(par_doc: rbml::Doc) -> InlinedItem { - let chi_doc = par_doc.get(c::tag_tree as usize); +fn decode_ast(item_doc: rbml::Doc) -> InlinedItem { + let chi_doc = item_doc.get(c::tag_tree as usize); let mut rbml_r = reader::Decoder::new(chi_doc); rbml_r.read_opaque(|decoder, _| Decodable::decode(decoder)).unwrap() } @@ -1280,8 +1282,8 @@ fn encode_item_ast(rbml_w: &mut Encoder, item: &hir::Item) { } #[cfg(test)] -fn decode_item_ast(par_doc: rbml::Doc) -> hir::Item { - let chi_doc = par_doc.get(c::tag_tree as usize); +fn decode_item_ast(item_doc: rbml::Doc) -> hir::Item { + let chi_doc = item_doc.get(c::tag_tree as usize); let mut d = reader::Decoder::new(chi_doc); Decodable::decode(&mut d).unwrap() } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index a0cbba279acc0..22a5289f02be8 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -73,6 +73,7 @@ pub const tag_crate_dep: usize = 0x35; pub const tag_crate_hash: usize = 0x103; // top-level only pub const tag_crate_crate_name: usize = 0x104; // top-level only +pub const tag_crate_disambiguator: usize = 0x113; // top-level only pub const tag_crate_dep_crate_name: usize = 0x36; pub const tag_crate_dep_hash: usize = 0x37; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d05728d11cd32..d07179749d9ab 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -21,7 +21,7 @@ use rustc::back::svh::Svh; use rustc::dep_graph::DepNode; use rustc::session::{config, Session}; use rustc::session::search_paths::PathKind; -use rustc::middle::cstore::{CrateStore, validate_crate_name}; +use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; use rustc::util::nodemap::FnvHashMap; use rustc::front::map as hir_map; @@ -38,7 +38,6 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::errors::FatalError; use syntax::parse::token::InternedString; -use syntax::util::small_vector::SmallVector; use rustc_front::intravisit::Visitor; use rustc_front::hir; use log; @@ -55,6 +54,7 @@ pub struct CrateReader<'a> { cstore: &'a CStore, next_crate_num: ast::CrateNum, foreign_item_map: FnvHashMap>, + local_crate_name: String, } impl<'a, 'b, 'hir> Visitor<'hir> for LocalCrateReader<'a, 'b> { @@ -146,12 +146,15 @@ impl PMDSource { } impl<'a> CrateReader<'a> { - pub fn new(sess: &'a Session, cstore: &'a CStore) -> CrateReader<'a> { + pub fn new(sess: &'a Session, + cstore: &'a CStore, + local_crate_name: &str) -> CrateReader<'a> { CrateReader { sess: sess, cstore: cstore, next_crate_num: cstore.next_crate_num(), foreign_item_map: FnvHashMap(), + local_crate_name: local_crate_name.to_owned(), } } @@ -272,6 +275,38 @@ impl<'a> CrateReader<'a> { } } + fn verify_no_symbol_conflicts(&self, + span: Span, + metadata: &MetadataBlob) { + let disambiguator = decoder::get_crate_disambiguator(metadata.as_slice()); + let crate_name = decoder::get_crate_name(metadata.as_slice()); + + // Check for (potential) conflicts with the local crate + if self.local_crate_name == crate_name && + self.sess.crate_disambiguator.get().as_str() == disambiguator { + span_fatal!(self.sess, span, E0519, + "the current crate is indistinguishable from one of its \ + dependencies: it has the same crate-name `{}` and was \ + compiled with the same `-C metadata` arguments. This \ + will result in symbol conflicts between the two.", + crate_name) + } + + let svh = decoder::get_crate_hash(metadata.as_slice()); + // Check for conflicts with any crate loaded so far + self.cstore.iter_crate_data(|_, other| { + if other.name() == crate_name && // same crate-name + other.disambiguator() == disambiguator && // same crate-disambiguator + other.hash() != svh { // but different SVH + span_fatal!(self.sess, span, E0523, + "found two different crates with name `{}` that are \ + not distinguished by differing `-C metadata`. This \ + will result in symbol conflicts between the two.", + crate_name) + } + }); + } + fn register_crate(&mut self, root: &Option, ident: &str, @@ -282,6 +317,7 @@ impl<'a> CrateReader<'a> { -> (ast::CrateNum, Rc, cstore::CrateSource) { self.verify_rustc_version(name, span, &lib.metadata); + self.verify_no_symbol_conflicts(span, &lib.metadata); // Claim this crate number and cache it let cnum = self.next_crate_num; @@ -307,15 +343,13 @@ impl<'a> CrateReader<'a> { let cmeta = Rc::new(cstore::crate_metadata { name: name.to_string(), - local_path: RefCell::new(SmallVector::zero()), - local_def_path: RefCell::new(vec![]), + extern_crate: Cell::new(None), index: decoder::load_index(metadata.as_slice()), xref_index: decoder::load_xrefs(metadata.as_slice()), data: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), - span: span, staged_api: staged_api, explicitly_linked: Cell::new(explicitly_linked), }); @@ -349,8 +383,7 @@ impl<'a> CrateReader<'a> { span: Span, kind: PathKind, explicitly_linked: bool) - -> (ast::CrateNum, Rc, - cstore::CrateSource) { + -> (ast::CrateNum, Rc, cstore::CrateSource) { enum LookupResult { Previous(ast::CrateNum), Loaded(loader::Library), @@ -407,23 +440,54 @@ impl<'a> CrateReader<'a> { } } + fn update_extern_crate(&mut self, + cnum: ast::CrateNum, + mut extern_crate: ExternCrate) + { + let cmeta = self.cstore.get_crate_data(cnum); + let old_extern_crate = cmeta.extern_crate.get(); + + // Prefer: + // - something over nothing (tuple.0); + // - direct extern crate to indirect (tuple.1); + // - shorter paths to longer (tuple.2). + let new_rank = (true, extern_crate.direct, !extern_crate.path_len); + let old_rank = match old_extern_crate { + None => (false, false, !0), + Some(ref c) => (true, c.direct, !c.path_len), + }; + + if old_rank >= new_rank { + return; // no change needed + } + + cmeta.extern_crate.set(Some(extern_crate)); + + // Propagate the extern crate info to dependencies. + extern_crate.direct = false; + for &dep_cnum in cmeta.cnum_map.borrow().values() { + self.update_extern_crate(dep_cnum, extern_crate); + } + } + // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(&mut self, root: &Option, - cdata: &[u8], span : Span) - -> cstore::cnum_map { + cdata: &[u8], + span : Span) + -> cstore::cnum_map { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers decoder::get_crate_deps(cdata).iter().map(|dep| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); let (local_cnum, _, _) = self.resolve_crate(root, - &dep.name, - &dep.name, - Some(&dep.hash), - span, - PathKind::Dependency, - dep.explicitly_linked); + &dep.name, + &dep.name, + Some(&dep.hash), + span, + PathKind::Dependency, + dep.explicitly_linked); (dep.cnum, local_cnum) }).collect() } @@ -713,12 +777,15 @@ impl<'a> CrateReader<'a> { } impl<'a, 'b> LocalCrateReader<'a, 'b> { - pub fn new(sess: &'a Session, cstore: &'a CStore, - map: &'a hir_map::Map<'b>) -> LocalCrateReader<'a, 'b> { + pub fn new(sess: &'a Session, + cstore: &'a CStore, + map: &'a hir_map::Map<'b>, + local_crate_name: &str) + -> LocalCrateReader<'a, 'b> { LocalCrateReader { sess: sess, cstore: cstore, - creader: CrateReader::new(sess, cstore), + creader: CrateReader::new(sess, cstore, local_crate_name), ast_map: map, } } @@ -762,19 +829,24 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { match self.creader.extract_crate_info_hir(i) { Some(info) => { - let (cnum, cmeta, _) = self.creader.resolve_crate(&None, - &info.ident, - &info.name, - None, - i.span, - PathKind::Crate, - true); + let (cnum, _, _) = self.creader.resolve_crate(&None, + &info.ident, + &info.name, + None, + i.span, + PathKind::Crate, + true); let def_id = self.ast_map.local_def_id(i.id); - let def_path = self.ast_map.def_path(def_id); - cmeta.update_local_def_path(def_path); - self.ast_map.with_path(i.id, |path| { - cmeta.update_local_path(path) - }); + + let len = self.ast_map.def_path(def_id).data.len(); + + self.creader.update_extern_crate(cnum, + ExternCrate { + def_id: def_id, + span: i.span, + direct: true, + path_len: len, + }); self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } None => () diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 9ac7216165caf..25cc2f91753a3 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -13,7 +13,7 @@ use decoder; use encoder; use loader; -use middle::cstore::{CrateStore, CrateSource, ChildItem, FoundAst}; +use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use middle::def; use middle::lang_items; @@ -128,16 +128,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_method_arg_names(&cdata, did.index) } - fn item_path(&self, def: DefId) -> Vec { + fn relative_item_path(&self, def: DefId) -> Vec { let cdata = self.get_crate_data(def.krate); - let path = decoder::get_item_path(&cdata, def.index); - - cdata.with_local_path(|cpath| { - let mut r = Vec::with_capacity(cpath.len() + path.len()); - r.extend_from_slice(cpath); - r.extend_from_slice(&path); - r - }) + decoder::get_item_path(&cdata, def.index) } fn extern_item_path(&self, def: DefId) -> Vec { @@ -334,9 +327,19 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_crate_attributes(self.get_crate_data(cnum).data()) } - fn crate_name(&self, cnum: ast::CrateNum) -> String + fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString + { + token::intern_and_get_ident(&self.get_crate_data(cnum).name[..]) + } + + fn original_crate_name(&self, cnum: ast::CrateNum) -> token::InternedString + { + token::intern_and_get_ident(&self.get_crate_data(cnum).name()) + } + + fn extern_crate(&self, cnum: ast::CrateNum) -> Option { - self.get_crate_data(cnum).name.clone() + self.get_crate_data(cnum).extern_crate.get() } fn crate_hash(&self, cnum: ast::CrateNum) -> Svh @@ -345,6 +348,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_crate_hash(cdata.data()) } + fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString + { + let cdata = self.get_crate_data(cnum); + token::intern_and_get_ident(decoder::get_crate_disambiguator(cdata.data())) + } + fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) -> FnvHashMap> { @@ -372,12 +381,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_reachable_ids(&cdata) } - fn def_path(&self, def: DefId) -> hir_map::DefPath - { + /// Returns the `DefKey` for a given `DefId`. This indicates the + /// parent `DefId` as well as some idea of what kind of data the + /// `DefId` refers to. + fn def_key(&self, def: DefId) -> hir_map::DefKey { + let cdata = self.get_crate_data(def.krate); + decoder::def_key(&cdata, def.index) + } + + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { let cdata = self.get_crate_data(def.krate); - let path = decoder::def_path(&cdata, def.index); - let local_path = cdata.local_def_path(); - local_path.into_iter().chain(path).collect() + decoder::def_path(&cdata, def.index) } fn variant_kind(&self, def_id: DefId) -> Option { @@ -478,9 +492,13 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { { loader::meta_section_name(target) } - fn encode_type(&self, tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec + fn encode_type(&self, + tcx: &TyCtxt<'tcx>, + ty: Ty<'tcx>, + def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String) + -> Vec { - encoder::encoded_ty(tcx, ty) + encoder::encoded_ty(tcx, ty, def_id_to_string) } fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)> diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index a96da6bf4d66a..f092ee3919826 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -21,7 +21,7 @@ use index; use loader; use rustc::back::svh::Svh; -use rustc::front::map as ast_map; +use rustc::middle::cstore::{ExternCrate}; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use std::cell::{RefCell, Ref, Cell}; @@ -31,9 +31,7 @@ use flate::Bytes; use syntax::ast; use syntax::attr; use syntax::codemap; -use syntax::parse::token; use syntax::parse::token::IdentInterner; -use syntax::util::small_vector::SmallVector; pub use middle::cstore::{NativeLibraryKind, LinkagePreference}; pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; @@ -63,13 +61,16 @@ pub struct ImportedFileMap { pub struct crate_metadata { pub name: String, - pub local_path: RefCell>, - pub local_def_path: RefCell, + + /// Information about the extern crate that caused this crate to + /// be loaded. If this is `None`, then the crate was injected + /// (e.g., by the allocator) + pub extern_crate: Cell>, + pub data: MetadataBlob, pub cnum_map: RefCell, pub cnum: ast::CrateNum, pub codemap_import_info: RefCell>, - pub span: codemap::Span, pub staged_api: bool, pub index: index::Index, @@ -248,8 +249,11 @@ impl CStore { impl crate_metadata { pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } - pub fn name(&self) -> String { decoder::get_crate_name(self.data()) } + pub fn name(&self) -> &str { decoder::get_crate_name(self.data()) } pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) } + pub fn disambiguator(&self) -> &str { + decoder::get_crate_disambiguator(self.data()) + } pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap) -> Ref<'a, Vec> { let filemaps = self.codemap_import_info.borrow(); @@ -265,50 +269,6 @@ impl crate_metadata { } } - pub fn with_local_path(&self, f: F) -> T - where F: Fn(&[ast_map::PathElem]) -> T - { - let cpath = self.local_path.borrow(); - if cpath.is_empty() { - let name = ast_map::PathMod(token::intern(&self.name)); - f(&[name]) - } else { - f(cpath.as_slice()) - } - } - - pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) { - let mut cpath = self.local_path.borrow_mut(); - let cap = cpath.len(); - match cap { - 0 => *cpath = candidate.collect(), - 1 => (), - _ => { - let candidate: SmallVector<_> = candidate.collect(); - if candidate.len() < cap { - *cpath = candidate; - } - }, - } - } - - pub fn local_def_path(&self) -> ast_map::DefPath { - let local_def_path = self.local_def_path.borrow(); - if local_def_path.is_empty() { - let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name)); - vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }] - } else { - local_def_path.clone() - } - } - - pub fn update_local_def_path(&self, candidate: ast_map::DefPath) { - let mut local_def_path = self.local_def_path.borrow_mut(); - if local_def_path.is_empty() || candidate.len() < local_def_path.len() { - *local_def_path = candidate; - } - } - pub fn is_allocator(&self) -> bool { let attrs = decoder::get_crate_attributes(self.data()); attr::contains_name(&attrs, "allocator") diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 0c736feeefeee..a4eeee44fb718 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -803,25 +803,43 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &TyCtxt<'tcx>, id: DefIndex) debug!("Looking up item: {:?}", id); let item_doc = cdata.lookup_item(id); let item_did = item_def_id(item_doc, cdata); + let parent_def_id = DefId { + krate: cdata.cnum, + index: def_key(cdata, id).parent.unwrap() + }; let mut parent_path = item_path(item_doc); parent_path.pop(); let mut parent_def_path = def_path(cdata, id); - parent_def_path.pop(); + parent_def_path.data.pop(); if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) { - let ii = decode_inlined_item(cdata, tcx, parent_path, + let ii = decode_inlined_item(cdata, + tcx, + parent_path, parent_def_path, - ast_doc, item_did); + parent_def_id, + ast_doc, + item_did); return FoundAst::Found(ii); } else if let Some(parent_did) = item_parent_item(cdata, item_doc) { // Remove the last element from the paths, since we are now // trying to inline the parent. - parent_path.pop(); - parent_def_path.pop(); + let grandparent_def_id = DefId { + krate: cdata.cnum, + index: def_key(cdata, parent_def_id.index).parent.unwrap() + }; + let mut grandparent_path = parent_path; + grandparent_path.pop(); + let mut grandparent_def_path = parent_def_path; + grandparent_def_path.data.pop(); let parent_doc = cdata.lookup_item(parent_did.index); if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, tag_ast as usize) { - let ii = decode_inlined_item(cdata, tcx, parent_path, - parent_def_path, - ast_doc, parent_did); + let ii = decode_inlined_item(cdata, + tcx, + grandparent_path, + grandparent_def_path, + grandparent_def_id, + ast_doc, + parent_did); if let &InlinedItem::Item(ref i) = ii { return FoundAst::FoundParent(parent_did, i); } @@ -1288,20 +1306,27 @@ pub fn get_crate_hash(data: &[u8]) -> Svh { Svh::new(hashdoc.as_str_slice()) } -pub fn maybe_get_crate_name(data: &[u8]) -> Option { +pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> { let cratedoc = rbml::Doc::new(data); reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| { - doc.as_str_slice().to_string() + doc.as_str_slice() }) } +pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str { + let crate_doc = rbml::Doc::new(data); + let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator); + let slice: &'a str = disambiguator_doc.as_str_slice(); + slice +} + pub fn get_crate_triple(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple); triple_doc.map(|s| s.as_str().to_string()) } -pub fn get_crate_name(data: &[u8]) -> String { +pub fn get_crate_name(data: &[u8]) -> &str { maybe_get_crate_name(data).expect("no crate name in crate") } @@ -1738,7 +1763,9 @@ pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &TyCtxt<'tcx>) .parse_closure_ty() } -fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey { +pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { + debug!("def_key: id={:?}", id); + let item_doc = cdata.lookup_item(id); match reader::maybe_get_doc(item_doc, tag_def_key) { Some(def_key_doc) => { let mut decoder = reader::Decoder::new(def_key_doc); @@ -1754,9 +1781,5 @@ fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey { pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath { debug!("def_path(id={:?})", id); - hir_map::definitions::make_def_path(id, |parent| { - debug!("def_path: parent={:?}", parent); - let parent_doc = cdata.lookup_item(parent); - def_key(parent_doc) - }) + hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent)) } diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 50b9ea5755086..8fa23de9a2d16 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -87,4 +87,6 @@ register_diagnostics! { E0468, // an `extern crate` loading macros must be at the crate root E0469, // imported macro not found E0470, // reexported macro not found + E0519, // local crate and dependency have same (crate-name, disambiguator) + E0523, // two dependencies have same (crate-name, disambiguator) but different SVH } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e677ea962f9cf..73ac64adbb2a5 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -143,7 +143,7 @@ pub fn def_to_u64(did: DefId) -> u64 { (did.krate as u64) << 32 | (did.index.as_usize() as u64) } -pub fn def_to_string(did: DefId) -> String { +pub fn def_to_string(_tcx: &TyCtxt, did: DefId) -> String { format!("{}:{}", did.krate, did.index.as_usize()) } @@ -1877,6 +1877,10 @@ fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) { rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name); } +fn encode_crate_disambiguator(rbml_w: &mut Encoder, crate_disambiguator: &str) { + rbml_w.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator); +} + fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) { rbml_w.wr_tagged_str(tag_crate_triple, triple); } @@ -1987,6 +1991,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, encode_crate_name(rbml_w, &ecx.link_meta.crate_name); encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple); encode_hash(rbml_w, &ecx.link_meta.crate_hash); + encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str()); encode_dylib_dependency_formats(rbml_w, &ecx); let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); @@ -2078,11 +2083,14 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, } // Get the encoded string for a type -pub fn encoded_ty<'tcx>(tcx: &TyCtxt<'tcx>, t: Ty<'tcx>) -> Vec { +pub fn encoded_ty<'tcx>(tcx: &TyCtxt<'tcx>, + t: Ty<'tcx>, + def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String) + -> Vec { let mut wr = Cursor::new(Vec::new()); tyencode::enc_ty(&mut wr, &tyencode::ctxt { diag: tcx.sess.diagnostic(), - ds: def_to_string, + ds: def_id_to_string, tcx: tcx, abbrevs: &RefCell::new(FnvHashMap()) }, t); diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 102bcc10face1..911ca7e315c1f 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -32,11 +32,11 @@ struct MacroLoader<'a> { } impl<'a> MacroLoader<'a> { - fn new(sess: &'a Session, cstore: &'a CStore) -> MacroLoader<'a> { + fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> { MacroLoader { sess: sess, span_whitelist: HashSet::new(), - reader: CrateReader::new(sess, cstore), + reader: CrateReader::new(sess, cstore, crate_name), macros: vec![], } } @@ -47,10 +47,13 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) { } /// Read exported macros. -pub fn read_macro_defs(sess: &Session, cstore: &CStore, krate: &ast::Crate) +pub fn read_macro_defs(sess: &Session, + cstore: &CStore, + krate: &ast::Crate, + crate_name: &str) -> Vec { - let mut loader = MacroLoader::new(sess, cstore); + let mut loader = MacroLoader::new(sess, cstore, crate_name); // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. Identify these by diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 4718732c8a037..67e77ba3315c9 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -37,7 +37,7 @@ use encoder; pub struct ctxt<'a, 'tcx: 'a> { pub diag: &'a Handler, // Def -> str Callback: - pub ds: fn(DefId) -> String, + pub ds: fn(&TyCtxt<'tcx>, DefId) -> String, // The type context. pub tcx: &'a TyCtxt<'tcx>, pub abbrevs: &'a abbrev_map<'tcx> @@ -99,7 +99,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx }; } ty::TyEnum(def, substs) => { - write!(w, "t[{}|", (cx.ds)(def.did)); + write!(w, "t[{}|", (cx.ds)(cx.tcx, def.did)); enc_substs(w, cx, substs); write!(w, "]"); } @@ -137,7 +137,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx } ty::TyFnDef(def_id, substs, f) => { write!(w, "F"); - write!(w, "{}|", (cx.ds)(def_id)); + write!(w, "{}|", (cx.ds)(cx.tcx, def_id)); enc_substs(w, cx, substs); enc_bare_fn_ty(w, cx, f); } @@ -152,12 +152,12 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx write!(w, "p[{}|{}|{}]", idx, space.to_uint(), name); } ty::TyStruct(def, substs) => { - write!(w, "a[{}|", (cx.ds)(def.did)); + write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did)); enc_substs(w, cx, substs); write!(w, "]"); } ty::TyClosure(def, ref substs) => { - write!(w, "k[{}|", (cx.ds)(def)); + write!(w, "k[{}|", (cx.ds)(cx.tcx, def)); enc_substs(w, cx, &substs.func_substs); for ty in &substs.upvar_tys { enc_ty(w, cx, ty); @@ -310,7 +310,7 @@ fn enc_bound_region(w: &mut Cursor>, cx: &ctxt, br: ty::BoundRegion) { } ty::BrNamed(d, name) => { write!(w, "[{}|{}]", - (cx.ds)(d), + (cx.ds)(cx.tcx, d), name); } ty::BrFresh(id) => { @@ -324,7 +324,7 @@ fn enc_bound_region(w: &mut Cursor>, cx: &ctxt, br: ty::BoundRegion) { pub fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, s: ty::TraitRef<'tcx>) { - write!(w, "{}|", (cx.ds)(s.def_id)); + write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id)); enc_substs(w, cx, s.substs); } @@ -408,8 +408,8 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut Cursor>, pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, v: &ty::TypeParameterDef<'tcx>) { write!(w, "{}:{}|{}|{}|{}|", - v.name, (cx.ds)(v.def_id), - v.space.to_uint(), v.index, (cx.ds)(v.default_def_id)); + v.name, (cx.ds)(cx.tcx, v.def_id), + v.space.to_uint(), v.index, (cx.ds)(cx.tcx, v.default_def_id)); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); enc_object_lifetime_default(w, cx, v.object_lifetime_default); } @@ -417,7 +417,7 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx> pub fn enc_region_param_def(w: &mut Cursor>, cx: &ctxt, v: &ty::RegionParameterDef) { write!(w, "{}:{}|{}|{}|", - v.name, (cx.ds)(v.def_id), + v.name, (cx.ds)(cx.tcx, v.def_id), v.space.to_uint(), v.index); for &r in &v.bounds { write!(w, "R"); @@ -477,7 +477,7 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, enc_ty(w, cx, data); } ty::Predicate::ObjectSafe(trait_def_id) => { - write!(w, "O{}|", (cx.ds)(trait_def_id)); + write!(w, "O{}|", (cx.ds)(cx.tcx, trait_def_id)); } } } diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index a950198a4e4f7..ac40215bbb1d0 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -44,9 +44,12 @@ fn call_malformed_plugin_attribute(a: &Session, b: Span) { } /// Read plugin metadata and dynamically load registrar functions. -pub fn load_plugins(sess: &Session, cstore: &CStore, krate: &ast::Crate, +pub fn load_plugins(sess: &Session, + cstore: &CStore, + krate: &ast::Crate, + crate_name: &str, addl_plugins: Option>) -> Vec { - let mut loader = PluginLoader::new(sess, cstore); + let mut loader = PluginLoader::new(sess, cstore, crate_name); for attr in &krate.attrs { if !attr.check_name("plugin") { @@ -82,10 +85,10 @@ pub fn load_plugins(sess: &Session, cstore: &CStore, krate: &ast::Crate, } impl<'a> PluginLoader<'a> { - fn new(sess: &'a Session, cstore: &'a CStore) -> PluginLoader<'a> { + fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> PluginLoader<'a> { PluginLoader { sess: sess, - reader: CrateReader::new(sess, cstore), + reader: CrateReader::new(sess, cstore, crate_name), plugins: vec![], } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index acb458f8cc6ee..64d117100543f 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -23,11 +23,8 @@ use session::Session; use middle::cstore::{self, CrateStore, LinkMeta}; use middle::cstore::{LinkagePreference, NativeLibraryKind}; use middle::dependency_format::Linkage; -use middle::ty::{Ty, TyCtxt}; -use rustc::front::map::DefPath; -use trans::{CrateContext, CrateTranslation, gensym_name}; +use trans::CrateTranslation; use util::common::time; -use util::sha2::{Digest, Sha256}; use util::fs::fix_windows_verbatim_for_gcc; use rustc_back::tempdir::TempDir; @@ -37,16 +34,13 @@ use std::env; use std::ffi::OsString; use std::fs; use std::io::{self, Read, Write}; -use std::iter::once; use std::mem; use std::path::{Path, PathBuf}; use std::process::Command; use std::str; use flate; -use serialize::hex::ToHex; use syntax::ast; use syntax::codemap::Span; -use syntax::parse::token::{self, InternedString}; use syntax::attr::AttrMetaMethods; use rustc_front::hir; @@ -81,58 +75,6 @@ pub const RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET: usize = RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET + 8; -/* - * Name mangling and its relationship to metadata. This is complex. Read - * carefully. - * - * 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 with the same name but different types need to get different - * linkage-names. We do this by hashing a string-encoding of the type into - * a fixed-size (currently 16-byte hex) cryptographic hash function (CHF: - * we use SHA256) to "prevent collisions". This is not airtight but 16 hex - * digits on uniform probability means you're going to need 2**32 same-name - * symbols in the same process before you're even hitting birthday-paradox - * collision probability. - * - * - Symbols in different crates but with same names "within" the crate need - * to get different linkage-names. - * - * - The hash shown in the filename needs to be predictable and stable for - * build tooling integration. It also needs to be using a hash function - * which is easy to use from Python, make, etc. - * - * So here is what we do: - * - * - Consider the package id; every crate has one (specified with crate_id - * attribute). If a package id isn't provided explicitly, we infer a - * versionless one from the output name. The version will end up being 0.0 - * in this case. CNAME and CVERS are taken from this package id. For - * example, github.com/mozilla/CNAME#CVERS. - * - * - Define CMH as SHA256(crateid). - * - * - Define CMH8 as the first 8 characters of CMH. - * - * - Compile our crate to lib CNAME-CMH8-CVERS.so - * - * - Define STH(sym) as SHA256(CMH, type_str(sym)) - * - * - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the - * name, non-name metadata, and type sense, and versioned in the way - * system linkers understand. - */ - pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String { @@ -188,187 +130,12 @@ pub fn build_link_meta(sess: &Session, -> LinkMeta { let r = LinkMeta { crate_name: name.to_owned(), - crate_hash: Svh::calculate(&sess.opts.cg.metadata, krate), + crate_hash: Svh::calculate(&sess.crate_disambiguator.get().as_str(), krate), }; info!("{:?}", r); return r; } -fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String { - let output = symbol_hasher.result_bytes(); - // 64 bits should be enough to avoid collisions. - output[.. 8].to_hex().to_string() -} - - -// This calculates STH for a symbol, as defined above -fn symbol_hash<'tcx>(tcx: &TyCtxt<'tcx>, - symbol_hasher: &mut Sha256, - t: Ty<'tcx>, - link_meta: &LinkMeta) - -> String { - // NB: do *not* use abbrevs here as we want the symbol names - // to be independent of one another in the crate. - - symbol_hasher.reset(); - symbol_hasher.input_str(&link_meta.crate_name); - symbol_hasher.input_str("-"); - symbol_hasher.input_str(link_meta.crate_hash.as_str()); - for meta in tcx.sess.crate_metadata.borrow().iter() { - symbol_hasher.input_str(&meta[..]); - } - symbol_hasher.input_str("-"); - symbol_hasher.input(&tcx.sess.cstore.encode_type(tcx, t)); - // Prefix with 'h' so that it never blends into adjacent digits - let mut hash = String::from("h"); - hash.push_str(&truncated_hash_result(symbol_hasher)); - hash -} - -fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> String { - if let Some(h) = ccx.type_hashcodes().borrow().get(&t) { - return h.to_string() - } - - let mut symbol_hasher = ccx.symbol_hasher().borrow_mut(); - let hash = symbol_hash(ccx.tcx(), &mut *symbol_hasher, t, ccx.link_meta()); - ccx.type_hashcodes().borrow_mut().insert(t, hash.clone()); - hash -} - - -// 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, ., _, $ -pub fn sanitize(s: &str) -> String { - let mut result = String::new(); - for c in s.chars() { - match c { - // Escape these with $ sequences - '@' => result.push_str("$SP$"), - '*' => result.push_str("$BP$"), - '&' => result.push_str("$RF$"), - '<' => result.push_str("$LT$"), - '>' => result.push_str("$GT$"), - '(' => result.push_str("$LP$"), - ')' => result.push_str("$RP$"), - ',' => result.push_str("$C$"), - - // '.' doesn't occur in types and functions, so reuse it - // for ':' and '-' - '-' | ':' => result.push('.'), - - // These are legal symbols - 'a' ... 'z' - | 'A' ... 'Z' - | '0' ... '9' - | '_' | '.' | '$' => result.push(c), - - _ => { - result.push('$'); - for c in c.escape_unicode().skip(1) { - match c { - '{' => {}, - '}' => result.push('$'), - c => result.push(c), - } - } - } - } - } - - // Underscore-qualify anything that didn't start as an ident. - if !result.is_empty() && - result.as_bytes()[0] != '_' as u8 && - ! (result.as_bytes()[0] as char).is_xid_start() { - return format!("_{}", &result[..]); - } - - return result; -} - -pub fn mangle>(path: PI, hash: Option<&str>) -> String { - // Follow C++ namespace-mangling style, see - // http://en.wikipedia.org/wiki/Name_mangling for more info. - // - // It turns out that on OSX 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. - - let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested - - fn push(n: &mut String, s: &str) { - let sani = sanitize(s); - n.push_str(&format!("{}{}", sani.len(), sani)); - } - - // First, connect each component with pairs. - for data in path { - push(&mut n, &data); - } - - if let Some(s) = hash { - push(&mut n, s) - } - - n.push('E'); // End name-sequence. - n -} - -pub fn exported_name(path: DefPath, hash: &str) -> String { - let path = path.into_iter() - .map(|e| e.data.as_interned_str()); - mangle(path, Some(hash)) -} - -pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: DefPath, - t: Ty<'tcx>, id: ast::NodeId) -> String { - let mut hash = get_symbol_hash(ccx, t); - - // Paths can be completely identical for different nodes, - // e.g. `fn foo() { { fn a() {} } { fn a() {} } }`, so we - // generate unique characters from the node id. For now - // hopefully 3 characters is enough to avoid collisions. - const EXTRA_CHARS: &'static str = - "abcdefghijklmnopqrstuvwxyz\ - ABCDEFGHIJKLMNOPQRSTUVWXYZ\ - 0123456789"; - let id = id as usize; - let extra1 = id % EXTRA_CHARS.len(); - let id = id / EXTRA_CHARS.len(); - let extra2 = id % EXTRA_CHARS.len(); - let id = id / EXTRA_CHARS.len(); - let extra3 = id % EXTRA_CHARS.len(); - hash.push(EXTRA_CHARS.as_bytes()[extra1] as char); - hash.push(EXTRA_CHARS.as_bytes()[extra2] as char); - hash.push(EXTRA_CHARS.as_bytes()[extra3] as char); - - exported_name(path, &hash[..]) -} - -pub fn mangle_internal_name_by_type_and_seq<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>, - name: &str) -> String { - let path = [token::intern(&t.to_string()).as_str(), gensym_name(name).as_str()]; - let hash = get_symbol_hash(ccx, t); - mangle(path.iter().cloned(), Some(&hash[..])) -} - -pub fn mangle_internal_name_by_path_and_seq(path: DefPath, flav: &str) -> String { - let names = - path.into_iter() - .map(|e| e.data.as_interned_str()) - .chain(once(gensym_name(flav).as_str())); // append unique version of "flav" - mangle(names, None) -} - pub fn get_linker(sess: &Session) -> (String, Command) { if let Some(ref linker) = sess.opts.cg.linker { (linker.clone(), Command::new(linker)) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index b6b330c3734b0..c6576b7fe0d97 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -359,6 +359,7 @@ impl<'a> Linker for MsvcLinker<'a> { for symbol in symbols { writeln!(f, " {}", symbol)?; } + Ok(()) })(); if let Err(e) = res { diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs new file mode 100644 index 0000000000000..13a82c0baaa26 --- /dev/null +++ b/src/librustc_trans/back/symbol_names.rs @@ -0,0 +1,378 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! 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` commandline 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 trans::{CrateContext, Instance, gensym_name}; +use util::sha2::{Digest, Sha256}; + +use rustc::middle::cstore; +use rustc::middle::def_id::DefId; +use rustc::middle::ty::{self, TypeFoldable}; +use rustc::middle::ty::item_path::{ItemPathBuffer, RootMode}; +use rustc::front::map::definitions::{DefPath, DefPathData}; + +use std::fmt::Write; +use syntax::parse::token::{self, InternedString}; +use serialize::hex::ToHex; + +pub fn def_id_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_id: DefId) -> String { + let def_path = tcx.def_path(def_id); + def_path_to_string(tcx, &def_path) +} + +pub fn def_path_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_path: &DefPath) -> String { + let mut s = String::with_capacity(def_path.data.len() * 16); + + s.push_str(&tcx.crate_name(def_path.krate)); + s.push_str("/"); + s.push_str(&tcx.crate_disambiguator(def_path.krate)); + + for component in &def_path.data { + write!(s, + "::{}[{}]", + component.data.as_interned_str(), + component.disambiguator) + .unwrap(); + } + + s +} + +fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + + // path to the item this name is for + def_path: &DefPath, + + // type of the item, without any generic + // parameters substituted; this is + // included in the hash as a kind of + // safeguard. + item_type: ty::Ty<'tcx>, + + // values for generic type parameters, + // if any. + parameters: &[ty::Ty<'tcx>]) + -> String { + debug!("get_symbol_hash(def_path={:?}, parameters={:?})", + def_path, parameters); + + let tcx = ccx.tcx(); + + let mut hash_state = ccx.symbol_hasher().borrow_mut(); + + hash_state.reset(); + + // the main symbol name is not necessarily unique; hash in the + // compiler's internal def-path, guaranteeing each symbol has a + // truly unique path + hash_state.input_str(&def_path_to_string(tcx, def_path)); + + // 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()); + let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string); + hash_state.input(&encoded_item_type[..]); + + // also include any type parameters (for generic items) + for t in parameters { + assert!(!t.has_erasable_regions()); + assert!(!t.needs_subst()); + let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string); + hash_state.input(&encoded_type[..]); + } + + return format!("h{}", truncated_hash_result(&mut *hash_state)); + + fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String { + let output = symbol_hasher.result_bytes(); + // 64 bits should be enough to avoid collisions. + output[.. 8].to_hex() + } +} + +fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: &Instance<'tcx>, + suffix: Option<&str>) + -> String { + let &Instance { def: mut def_id, params: parameters } = instance; + + debug!("exported_name_with_opt_suffix(def_id={:?}, parameters={:?}, suffix={:?})", + def_id, parameters, suffix); + + if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { + if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) { + def_id = src_def_id; + } + } + + let def_path = ccx.tcx().def_path(def_id); + assert_eq!(def_path.krate, def_id.krate); + + // 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 = ccx.tcx().def_key(ty_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) | + DefPathData::ValueNs(_) => { + instance_ty = ccx.tcx().lookup_item_type(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(|| { + panic!("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 = ccx.tcx().erase_regions(&instance_ty.ty); + + let hash = get_symbol_hash(ccx, &def_path, instance_ty, parameters.as_slice()); + + let mut buffer = SymbolPathBuffer { + names: Vec::with_capacity(def_path.data.len()) + }; + ccx.tcx().push_item_path(&mut buffer, def_id); + + if let Some(suffix) = suffix { + buffer.push(suffix); + } + + mangle(buffer.names.into_iter(), Some(&hash[..])) +} + +struct SymbolPathBuffer { + names: Vec, +} + +impl ItemPathBuffer for SymbolPathBuffer { + fn root_mode(&self) -> &RootMode { + const ABSOLUTE: &'static RootMode = &RootMode::Absolute; + ABSOLUTE + } + + fn push(&mut self, text: &str) { + self.names.push(token::intern(text).as_str()); + } +} + +pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: &Instance<'tcx>) + -> String { + exported_name_with_opt_suffix(ccx, instance, None) +} + +pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: &Instance<'tcx>, + suffix: &str) + -> String { + exported_name_with_opt_suffix(ccx, instance, Some(suffix)) +} + +/// Only symbols that are invisible outside their compilation unit should use a +/// name generated by this function. +pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + t: ty::Ty<'tcx>, + suffix: &str) + -> String { + let path = [token::intern(&t.to_string()).as_str(), + gensym_name(suffix).as_str()]; + let def_path = DefPath { + data: vec![], + krate: cstore::LOCAL_CRATE, + }; + let hash = get_symbol_hash(ccx, &def_path, t, &[]); + mangle(path.iter().cloned(), Some(&hash[..])) +} + +// 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, ., _, $ +pub fn sanitize(s: &str) -> String { + let mut result = String::new(); + for c in s.chars() { + match c { + // Escape these with $ sequences + '@' => result.push_str("$SP$"), + '*' => result.push_str("$BP$"), + '&' => result.push_str("$RF$"), + '<' => result.push_str("$LT$"), + '>' => result.push_str("$GT$"), + '(' => result.push_str("$LP$"), + ')' => result.push_str("$RP$"), + ',' => result.push_str("$C$"), + + // '.' doesn't occur in types and functions, so reuse it + // for ':' and '-' + '-' | ':' => result.push('.'), + + // These are legal symbols + 'a' ... 'z' + | 'A' ... 'Z' + | '0' ... '9' + | '_' | '.' | '$' => result.push(c), + + _ => { + result.push('$'); + for c in c.escape_unicode().skip(1) { + match c { + '{' => {}, + '}' => result.push('$'), + c => result.push(c), + } + } + } + } + } + + // Underscore-qualify anything that didn't start as an ident. + if !result.is_empty() && + result.as_bytes()[0] != '_' as u8 && + ! (result.as_bytes()[0] as char).is_xid_start() { + return format!("_{}", &result[..]); + } + + return result; +} + +pub fn mangle>(path: PI, hash: Option<&str>) -> String { + // Follow C++ namespace-mangling style, see + // http://en.wikipedia.org/wiki/Name_mangling for more info. + // + // It turns out that on OSX 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. + + let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested + + fn push(n: &mut String, s: &str) { + let sani = sanitize(s); + n.push_str(&format!("{}{}", sani.len(), sani)); + } + + // First, connect each component with pairs. + for data in path { + push(&mut n, &data); + } + + if let Some(s) = hash { + push(&mut n, s) + } + + n.push('E'); // End name-sequence. + n +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f8bbde6010940..b9f92bcc4d961 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -69,6 +69,7 @@ pub mod back { pub mod linker; pub mod link; pub mod lto; + pub mod symbol_names; pub mod write; pub mod msvc; } diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 78e91e00baa71..4bbb762469373 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -90,7 +90,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { for n in self.tcx.sess.cstore.crates() { result.push(CrateData { - name: self.tcx.sess.cstore.crate_name(n), + name: (&self.tcx.sess.cstore.crate_name(n)[..]).to_owned(), number: n, }); } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 1d8daf9d86b4a..7231304ec4c4f 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + //! Translate the completed AST to the LLVM IR. //! //! Some functions here, such as trans_block and trans_expr, return a value -- @@ -29,8 +30,7 @@ pub use self::ValueOrigin::*; use super::CrateTranslation; use super::ModuleTranslation; -use back::link::mangle_exported_name; -use back::link; +use back::{link, symbol_names}; use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; @@ -84,6 +84,7 @@ use trans::machine::{llalign_of_min, llsize_of, llsize_of_real}; use trans::meth; use trans::mir; use trans::monomorphize::{self, Instance}; +use trans::symbol_names_test; use trans::tvec; use trans::type_::Type; use trans::type_of; @@ -2421,10 +2422,11 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { } pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - id: ast::NodeId, - ty: Ty<'tcx>, + instance: Instance<'tcx>, attrs: &[ast::Attribute]) -> String { + let id = ccx.tcx().map.as_local_node_id(instance.def).unwrap(); + match ccx.external_srcs().borrow().get(&id) { Some(&did) => { let sym = ccx.sess().cstore.item_symbol(did); @@ -2438,16 +2440,16 @@ pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Use provided name Some(name) => name.to_string(), _ => { - let path = ccx.tcx().map.def_path_from_id(id); if attr::contains_name(attrs, "no_mangle") { // Don't mangle - path.last().unwrap().data.to_string() + let path = ccx.tcx().map.def_path_from_id(id); + path.data.last().unwrap().data.to_string() } else { match weak_lang_items::link_name(attrs) { Some(name) => name.to_string(), None => { // Usual name mangling - mangle_exported_name(ccx, path, ty, id) + symbol_names::exported_name(ccx, &instance) } } } @@ -2755,6 +2757,8 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, } collector::print_collection_results(&ccx); + + symbol_names_test::report_symbol_names(&ccx); } for ccx in shared_ccx.iter() { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 1013c5d64b609..6fe4598c1ba3c 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -18,7 +18,7 @@ pub use self::CalleeData::*; pub use self::CallArgs::*; use arena::TypedArena; -use back::link; +use back::symbol_names; use llvm::{self, ValueRef, get_params}; use middle::cstore::LOCAL_CRATE; use middle::def_id::DefId; @@ -378,8 +378,10 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("tuple_fn_ty: {:?}", tuple_fn_ty); // - let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, - "fn_pointer_shim"); + let function_name = + symbol_names::internal_name_from_type_and_suffix(ccx, + bare_fn_ty, + "fn_pointer_shim"); let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty); // @@ -513,7 +515,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Some(hir_map::NodeImplItem(&hir::ImplItem { ref attrs, id, span, node: hir::ImplItemKind::Method(..), .. })) => { - let sym = exported_name(ccx, id, ty, attrs); + let sym = exported_name(ccx, instance, attrs); if declare::get_defined_value(ccx, &sym).is_some() { ccx.sess().span_fatal(span, diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index dbabc3f54c594..ff3235385a9b0 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -9,7 +9,7 @@ // except according to those terms. use arena::TypedArena; -use back::link::{self, mangle_internal_name_by_path_and_seq}; +use back::symbol_names; use llvm::{ValueRef, get_param, get_params}; use middle::def_id::DefId; use middle::infer; @@ -152,8 +152,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let path = tcx.def_path(closure_id); - let symbol = mangle_internal_name_by_path_and_seq(path, "closure"); + let symbol = symbol_names::exported_name(ccx, &instance); // Compute the rust-call form of the closure call method. let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any); @@ -383,7 +382,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( }); // Create the by-value helper. - let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); + let function_name = + symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim"); let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); let (block_arena, fcx): (TypedArena<_>, FunctionContext); diff --git a/src/librustc_trans/trans/collector.rs b/src/librustc_trans/trans/collector.rs index ab8f7d6bec3d5..3f3da36be0695 100644 --- a/src/librustc_trans/trans/collector.rs +++ b/src/librustc_trans/trans/collector.rs @@ -1261,28 +1261,20 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn push_item_name(ccx: &CrateContext, def_id: DefId, output: &mut String) { - if def_id.is_local() { - let node_id = ccx.tcx().map.as_local_node_id(def_id).unwrap(); - let inlined_from = ccx.external_srcs() - .borrow() - .get(&node_id) - .map(|def_id| *def_id); - - if let Some(extern_def_id) = inlined_from { - push_item_name(ccx, extern_def_id, output); - return; - } + let def_path = ccx.tcx().def_path(def_id); - output.push_str(&ccx.link_meta().crate_name); - output.push_str("::"); - } + // some_crate:: + output.push_str(&ccx.tcx().crate_name(def_path.krate)); + output.push_str("::"); - for part in ccx.tcx().def_path(def_id) { + // foo::bar::ItemName:: + for part in ccx.tcx().def_path(def_id).data { output.push_str(&format!("{}[{}]::", part.data.as_interned_str(), part.disambiguator)); } + // remove final "::" output.pop(); output.pop(); } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 7e6b24969100b..4cdb64a9bfb71 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -1032,7 +1032,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) // we need to get the symbol from metadata instead of // using the current crate's name/version // information in the hash of the symbol - let sym = exported_name(ccx, id, ty, attrs); + let sym = exported_name(ccx, instance, attrs); debug!("making {}", sym); // Create the global before evaluating the initializer; diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 046e05dd0710a..a3d387afa96f7 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -25,7 +25,8 @@ use trans::debuginfo; use trans::declare; use trans::glue::DropGlueKind; use trans::mir::CachedMir; -use trans::monomorphize::Instance; +use trans::Instance; + use trans::collector::{TransItem, TransItemState}; use trans::type_::{Type, TypeNames}; use middle::subst::{Substs, VecPerParamSpace}; diff --git a/src/librustc_trans/trans/debuginfo/gdb.rs b/src/librustc_trans/trans/debuginfo/gdb.rs index 4e3fadd0fa911..7740f2775866c 100644 --- a/src/librustc_trans/trans/debuginfo/gdb.rs +++ b/src/librustc_trans/trans/debuginfo/gdb.rs @@ -90,10 +90,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) pub fn needs_gdb_debug_scripts_section(ccx: &CrateContext) -> bool { let omit_gdb_pretty_printer_section = - attr::contains_name(&ccx.tcx() - .map - .krate() - .attrs, + attr::contains_name(&ccx.tcx().map.krate_attrs(), "omit_gdb_pretty_printer_section"); !omit_gdb_pretty_printer_section && diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index de4b1ba858a6c..aa205898114d6 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -14,7 +14,7 @@ use std; -use back::link; +use back::symbol_names; use llvm; use llvm::{ValueRef, get_param}; use middle::lang_items::ExchangeFreeFnLangItem; @@ -259,7 +259,12 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; }; - let fn_nm = link::mangle_internal_name_by_type_and_seq(ccx, t, "drop"); + let suffix = match g { + DropGlueKind::Ty(_) => "drop", + DropGlueKind::TyContents(_) => "drop_contents", + }; + + let fn_nm = symbol_names::internal_name_from_type_and_suffix(ccx, t, suffix); assert!(declare::get_defined_value(ccx, &fn_nm).is_none()); let llfn = declare::declare_cfn(ccx, &fn_nm, llfnty); ccx.available_drop_glues().borrow_mut().insert(g, fn_nm); diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 530b99cba920c..a9c94a4522ba9 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -97,6 +97,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { if ty_v.did == fn_id { my_id = ast_v.node.data.id(); } ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id())); + ccx.external_srcs().borrow_mut().insert(ast_v.node.data.id(), ty_v.did); } } hir::ItemStruct(ref struct_def, _) => { @@ -105,6 +106,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { non-tuple struct") } else { ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id())); + ccx.external_srcs().borrow_mut().insert(struct_def.id(), fn_id); my_id = struct_def.id(); } } diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index ae619ceb30b01..f45de10bca853 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -11,7 +11,7 @@ use std::rc::Rc; use arena::TypedArena; -use back::link; +use back::symbol_names; use llvm::{ValueRef, get_params}; use middle::def_id::DefId; use middle::infer; @@ -89,7 +89,8 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, let sig = infer::normalize_associated_type(tcx, &sig); let fn_ty = FnType::new(ccx, method_ty.fn_abi(), &sig, &[]); - let function_name = link::mangle_internal_name_by_type_and_seq(ccx, method_ty, "object_shim"); + let function_name = + symbol_names::internal_name_from_type_and_suffix(ccx, method_ty, "object_shim"); let llfn = declare::define_internal_fn(ccx, &function_name, method_ty); let empty_substs = tcx.mk_substs(Substs::empty()); diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index c5ab0d4e74421..930f37ce25634 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -15,6 +15,7 @@ pub use self::base::trans_crate; pub use self::context::CrateContext; pub use self::common::gensym_name; pub use self::disr::Disr; +pub use self::monomorphize::Instance; #[macro_use] mod macros; @@ -58,6 +59,7 @@ mod meth; mod mir; mod monomorphize; mod collector; +mod symbol_names_test; mod tvec; mod type_; mod type_of; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 63fb8c5fb5e1c..6dd8d651012e0 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use back::link::exported_name; +use back::symbol_names; use llvm::ValueRef; use llvm; use middle::def_id::DefId; use middle::infer::normalize_associated_type; use middle::subst; use middle::subst::{Subst, Substs}; +use middle::ty::{self, Ty, TyCtxt}; use middle::ty::fold::{TypeFolder, TypeFoldable}; use trans::attributes; use trans::base::{push_ctxt}; @@ -22,7 +23,6 @@ use trans::base::trans_fn; use trans::base; use trans::common::*; use trans::declare; -use middle::ty::{self, Ty, TyCtxt}; use trans::Disr; use rustc::front::map as hir_map; use rustc::util::ppaux; @@ -33,7 +33,6 @@ use syntax::attr; use syntax::errors; use std::fmt; -use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: DefId, @@ -90,22 +89,13 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, monomorphizing.insert(fn_id, depth + 1); } - let hash; - let s = { - let mut state = SipHasher::new(); - instance.hash(&mut state); - mono_ty.hash(&mut state); - - hash = format!("h{}", state.finish()); - let path = ccx.tcx().map.def_path(fn_id); - exported_name(path, &hash[..]) - }; + let symbol = symbol_names::exported_name(ccx, &instance); - debug!("monomorphize_fn mangled to {}", s); - assert!(declare::get_defined_value(ccx, &s).is_none()); + debug!("monomorphize_fn mangled to {}", symbol); + assert!(declare::get_defined_value(ccx, &symbol).is_none()); // FIXME(nagisa): perhaps needs a more fine grained selection? - let lldecl = declare::define_internal_fn(ccx, &s, mono_ty); + let lldecl = declare::define_internal_fn(ccx, &symbol, mono_ty); // FIXME(eddyb) Doubt all extern fn should allow unwinding. attributes::unwind(lldecl, true); @@ -137,9 +127,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); attributes::from_fn_attrs(ccx, attrs, lldecl); - let is_first = !ccx.available_monomorphizations().borrow().contains(&s); + let is_first = !ccx.available_monomorphizations().borrow() + .contains(&symbol); if is_first { - ccx.available_monomorphizations().borrow_mut().insert(s.clone()); + ccx.available_monomorphizations().borrow_mut().insert(symbol.clone()); } let trans_everywhere = attr::requests_inline(attrs); diff --git a/src/librustc_trans/trans/symbol_names_test.rs b/src/librustc_trans/trans/symbol_names_test.rs new file mode 100644 index 0000000000000..63abbfd53b6fa --- /dev/null +++ b/src/librustc_trans/trans/symbol_names_test.rs @@ -0,0 +1,86 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Walks the crate looking for items/impl-items/trait-items that have +//! either a `rustc_symbol_name` or `rustc_item_path` attribute and +//! generates an error giving, respectively, the symbol name or +//! item-path. This is used for unit testing the code that generates +//! paths etc in all kinds of annoying scenarios. + +use back::symbol_names; +use rustc::middle::ty::TyCtxt; +use rustc_front::hir; +use rustc_front::intravisit::{self, Visitor}; +use syntax::ast; +use syntax::attr::AttrMetaMethods; +use trans::common::CrateContext; +use trans::monomorphize::Instance; + +const SYMBOL_NAME: &'static str = "rustc_symbol_name"; +const ITEM_PATH: &'static str = "rustc_item_path"; + +pub fn report_symbol_names(ccx: &CrateContext) { + // if the `rustc_attrs` feature is not enabled, then the + // attributes we are interested in cannot be present anyway, so + // skip the walk. + let tcx = ccx.tcx(); + if !tcx.sess.features.borrow().rustc_attrs { + return; + } + + let _ignore = tcx.dep_graph.in_ignore(); + let mut visitor = SymbolNamesTest { ccx: ccx, tcx: tcx }; + tcx.map.krate().visit_all_items(&mut visitor); +} + +struct SymbolNamesTest<'a, 'tcx:'a> { + ccx: &'a CrateContext<'a, 'tcx>, + tcx: &'a TyCtxt<'tcx>, +} + +impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { + fn process_attrs(&mut self, + node_id: ast::NodeId) { + let def_id = self.tcx.map.local_def_id(node_id); + for attr in self.tcx.get_attrs(def_id).iter() { + if attr.check_name(SYMBOL_NAME) { + // for now, can only use on monomorphic names + let instance = Instance::mono(self.tcx, def_id); + let name = symbol_names::exported_name(self.ccx, &instance); + self.tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); + } else if attr.check_name(ITEM_PATH) { + let path = self.tcx.item_path_str(def_id); + self.tcx.sess.span_err(attr.span, &format!("item-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<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> { + fn visit_item(&mut self, item: &'tcx hir::Item) { + self.process_attrs(item.id); + intravisit::walk_item(self, item); + } + + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { + self.process_attrs(ti.id); + intravisit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { + self.process_attrs(ii.id); + intravisit::walk_impl_item(self, ii) + } +} + diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 15aeca9204a64..aab5c960df353 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -241,7 +241,7 @@ impl Clean for CrateNum { } }); ExternalCrate { - name: cx.sess().cstore.crate_name(self.0), + name: (&cx.sess().cstore.crate_name(self.0)[..]).to_owned(), attrs: cx.sess().cstore.crate_attrs(self.0).clean(cx), primitives: primitives, } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 299b7d8b9ba07..80e1ae111a2d8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -349,6 +349,10 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat "the `#[rustc_if_this_changed]` attribute \ is just used for rustc unit tests \ and will never be stable")), + ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs", + "internal rustc attributes will never be stable")), + ("rustc_item_path", Whitelisted, Gated("rustc_attrs", + "internal rustc attributes will never be stable")), ("rustc_move_fragments", Normal, Gated("rustc_attrs", "the `#[rustc_move_fragments]` attribute \ is just used for rustc unit tests \ @@ -579,6 +583,7 @@ pub struct Features { pub const_indexing: bool, pub static_recursion: bool, pub default_type_parameter_fallback: bool, + pub rustc_attrs: bool, pub type_macros: bool, pub cfg_target_feature: bool, pub cfg_target_vendor: bool, @@ -614,6 +619,7 @@ impl Features { const_indexing: false, static_recursion: false, default_type_parameter_fallback: false, + rustc_attrs: false, type_macros: false, cfg_target_feature: false, cfg_target_vendor: false, @@ -1225,6 +1231,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, const_indexing: cx.has_feature("const_indexing"), static_recursion: cx.has_feature("static_recursion"), default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), + rustc_attrs: cx.has_feature("rustc_attrs"), type_macros: cx.has_feature("type_macros"), cfg_target_feature: cx.has_feature("cfg_target_feature"), cfg_target_vendor: cx.has_feature("cfg_target_vendor"), diff --git a/src/test/auxiliary/inline-default-methods.rs b/src/test/auxiliary/inline-default-methods.rs index 5f1bd7ab52235..e21e6ad204384 100644 --- a/src/test/auxiliary/inline-default-methods.rs +++ b/src/test/auxiliary/inline-default-methods.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + pub trait Foo { fn bar(&self); fn foo(&mut self) {} diff --git a/src/test/auxiliary/issue-13698.rs b/src/test/auxiliary/issue-13698.rs index 0bb2133c833c7..ecddfe99b3be7 100644 --- a/src/test/auxiliary/issue-13698.rs +++ b/src/test/auxiliary/issue-13698.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + pub trait Foo { #[doc(hidden)] fn foo(&self) {} diff --git a/src/test/auxiliary/issue-15318.rs b/src/test/auxiliary/issue-15318.rs index 9e42dbfbc6be4..145b4df629995 100644 --- a/src/test/auxiliary/issue-15318.rs +++ b/src/test/auxiliary/issue-15318.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + #![doc(html_root_url = "http://example.com/")] /// dox diff --git a/src/test/auxiliary/issue-17476.rs b/src/test/auxiliary/issue-17476.rs index d3a860357422c..644d1634e9d9c 100644 --- a/src/test/auxiliary/issue-17476.rs +++ b/src/test/auxiliary/issue-17476.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux #![doc(html_root_url = "http://example.com")] diff --git a/src/test/auxiliary/issue-17718.rs b/src/test/auxiliary/issue-17718-aux.rs similarity index 100% rename from src/test/auxiliary/issue-17718.rs rename to src/test/auxiliary/issue-17718-aux.rs diff --git a/src/test/auxiliary/issue-19190-3.rs b/src/test/auxiliary/issue-19190-3.rs index 7403bcf4afb31..2c9271202a650 100644 --- a/src/test/auxiliary/issue-19190-3.rs +++ b/src/test/auxiliary/issue-19190-3.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + use std::ops::Deref; pub struct Foo; diff --git a/src/test/auxiliary/issue-20646.rs b/src/test/auxiliary/issue-20646.rs index 150d8018f0888..815b78a91d9af 100644 --- a/src/test/auxiliary/issue-20646.rs +++ b/src/test/auxiliary/issue-20646.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + pub trait Trait { type Output; } diff --git a/src/test/auxiliary/issue-20727.rs b/src/test/auxiliary/issue-20727.rs index aea8b429d9f75..2ec761fad96b5 100644 --- a/src/test/auxiliary/issue-20727.rs +++ b/src/test/auxiliary/issue-20727.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + pub trait Deref { type Target: ?Sized; diff --git a/src/test/auxiliary/issue-21092.rs b/src/test/auxiliary/issue-21092.rs index 6d6046cc7bfc2..e906311e3aeb4 100644 --- a/src/test/auxiliary/issue-21092.rs +++ b/src/test/auxiliary/issue-21092.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + pub trait Foo { type Bar; fn foo(&self) {} diff --git a/src/test/auxiliary/issue-21801.rs b/src/test/auxiliary/issue-21801.rs index ada6c6925025d..f618edec5985e 100644 --- a/src/test/auxiliary/issue-21801.rs +++ b/src/test/auxiliary/issue-21801.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + pub struct Foo; impl Foo { diff --git a/src/test/auxiliary/issue-22025.rs b/src/test/auxiliary/issue-22025.rs index 554b580ae2b1f..35a37e27d912f 100644 --- a/src/test/auxiliary/issue-22025.rs +++ b/src/test/auxiliary/issue-22025.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + pub mod foo { pub trait Foo {} diff --git a/src/test/auxiliary/issue-27362.rs b/src/test/auxiliary/issue-27362.rs index e551d623ae7db..25de698cad10e 100644 --- a/src/test/auxiliary/issue-27362.rs +++ b/src/test/auxiliary/issue-27362.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + #![feature(const_fn)] pub const fn foo() {} diff --git a/src/test/auxiliary/issue-29584.rs b/src/test/auxiliary/issue-29584.rs index 4a9e6126fc602..63c79f875efb2 100644 --- a/src/test/auxiliary/issue-29584.rs +++ b/src/test/auxiliary/issue-29584.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Cmetadata=aux + pub struct Foo; #[doc(hidden)] diff --git a/src/test/auxiliary/typeid-intrinsic.rs b/src/test/auxiliary/typeid-intrinsic-aux1.rs similarity index 100% rename from src/test/auxiliary/typeid-intrinsic.rs rename to src/test/auxiliary/typeid-intrinsic-aux1.rs diff --git a/src/test/auxiliary/typeid-intrinsic2.rs b/src/test/auxiliary/typeid-intrinsic-aux2.rs similarity index 100% rename from src/test/auxiliary/typeid-intrinsic2.rs rename to src/test/auxiliary/typeid-intrinsic-aux2.rs diff --git a/src/test/codegen-units/cross-crate-closures.rs b/src/test/codegen-units/cross-crate-closures.rs index 32b07d42fec44..30f3ef12d0743 100644 --- a/src/test/codegen-units/cross-crate-closures.rs +++ b/src/test/codegen-units/cross-crate-closures.rs @@ -19,12 +19,12 @@ extern crate cgu_extern_closures; //~ TRANS_ITEM fn cross_crate_closures::main[0] fn main() { - //~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn[0] - //~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn[0]::{{closure}}[0] + //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0] + //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0]::{{closure}}[0] let _ = cgu_extern_closures::inlined_fn(1, 2); - //~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn_generic[0] - //~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn_generic[0]::{{closure}}[0] + //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn_generic[0] + //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn_generic[0]::{{closure}}[0] let _ = cgu_extern_closures::inlined_fn_generic(3, 4, 5i32); // Nothing should be generated for this call, we just link to the instance instance diff --git a/src/test/codegen-units/cross-crate-generic-functions.rs b/src/test/codegen-units/cross-crate-generic-functions.rs index 82d940a154852..ada1234b852a1 100644 --- a/src/test/codegen-units/cross-crate-generic-functions.rs +++ b/src/test/codegen-units/cross-crate-generic-functions.rs @@ -19,12 +19,12 @@ extern crate cgu_generic_function; //~ TRANS_ITEM fn cross_crate_generic_functions::main[0] fn main() { - //~ TRANS_ITEM fn cgu_generic_function[0]::bar[0] - //~ TRANS_ITEM fn cgu_generic_function[0]::foo[0] + //~ TRANS_ITEM fn cgu_generic_function::bar[0] + //~ TRANS_ITEM fn cgu_generic_function::foo[0] let _ = cgu_generic_function::foo(1u32); - //~ TRANS_ITEM fn cgu_generic_function[0]::bar[0] - //~ TRANS_ITEM fn cgu_generic_function[0]::foo[0] + //~ TRANS_ITEM fn cgu_generic_function::bar[0] + //~ TRANS_ITEM fn cgu_generic_function::foo[0] let _ = cgu_generic_function::foo(2u64); // This should not introduce a codegen item diff --git a/src/test/codegen-units/cross-crate-trait-method.rs b/src/test/codegen-units/cross-crate-trait-method.rs index aa1f6b06c8135..9f29a90bffbf6 100644 --- a/src/test/codegen-units/cross-crate-trait-method.rs +++ b/src/test/codegen-units/cross-crate-trait-method.rs @@ -29,31 +29,31 @@ fn main() // Currently, no object code is generated for trait methods with default // implemenations, unless they are actually called from somewhere. Therefore // we cannot import the implementations and have to create our own inline. - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] let _ = Trait::with_default_impl(0u32); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] let _ = Trait::with_default_impl('c'); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic(0u32, "abc"); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic(0u32, false); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic('x', 1i16); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic('y', 0i32); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::u32.Trait[0]::without_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] let _: (u32, char) = Trait::without_default_impl_generic('c'); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::u32.Trait[0]::without_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] let _: (u32, bool) = Trait::without_default_impl_generic(false); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::char.Trait[0]::without_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] let _: (char, char) = Trait::without_default_impl_generic('c'); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::char.Trait[0]::without_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] let _: (char, bool) = Trait::without_default_impl_generic(false); } diff --git a/src/test/codegen-units/generic-drop-glue.rs b/src/test/codegen-units/generic-drop-glue.rs index f89d6e61bc552..476c84044e686 100644 --- a/src/test/codegen-units/generic-drop-glue.rs +++ b/src/test/codegen-units/generic-drop-glue.rs @@ -49,17 +49,17 @@ struct NonGenericWithDrop(i32); impl Drop for NonGenericWithDrop { fn drop(&mut self) {} -//~ TRANS_ITEM fn generic_drop_glue::NonGenericWithDrop.Drop[0]::drop[0] +//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0] } //~ TRANS_ITEM fn generic_drop_glue::main[0] fn main() { //~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0] - //~ TRANS_ITEM fn generic_drop_glue::StructWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0] let _ = StructWithDrop { x: 0i8, y: 'a' }.x; //~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> - //~ TRANS_ITEM fn generic_drop_glue::StructWithDrop.Drop[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> + //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y; // Should produce no drop glue @@ -71,14 +71,14 @@ fn main() { let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y; //~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0] - //~ TRANS_ITEM fn generic_drop_glue::EnumWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::A::(0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as i32 }; //~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0] - //~ TRANS_ITEM fn generic_drop_glue::EnumWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::B::(1.0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as f64 diff --git a/src/test/codegen-units/generic-impl.rs b/src/test/codegen-units/generic-impl.rs index 6e6bb5cbf53c8..a27515fd39b70 100644 --- a/src/test/codegen-units/generic-impl.rs +++ b/src/test/codegen-units/generic-impl.rs @@ -40,11 +40,11 @@ pub struct LifeTimeOnly<'a> { impl<'a> LifeTimeOnly<'a> { - //~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::foo[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::foo[0] pub fn foo(&self) {} - //~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::bar[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::bar[0] pub fn bar(&'a self) {} - //~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::baz[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::baz[0] pub fn baz<'b>(&'b self) {} pub fn non_instantiated(&self) {} @@ -53,27 +53,27 @@ impl<'a> LifeTimeOnly<'a> { //~ TRANS_ITEM fn generic_impl::main[0] fn main() { - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::Struct[0]::get[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new(0i32).get(0i16); - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::Struct[0]::get[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new(0i64).get(0i16); - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::Struct[0]::get[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new('c').get(0i16); - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0]<&str> + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<&str> //~ TRANS_ITEM fn generic_impl::id[0]<&str> - //~ TRANS_ITEM fn generic_impl::Struct[0]::get[0], i16> + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0], i16> let _ = Struct::new(Struct::new("str")).get(0i16); - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0]> + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]> //~ TRANS_ITEM fn generic_impl::id[0]> let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str")); } diff --git a/src/test/codegen-units/impl-in-non-instantiated-generic.rs b/src/test/codegen-units/impl-in-non-instantiated-generic.rs index e17a1a7094f2f..a3bfa67e1ae44 100644 --- a/src/test/codegen-units/impl-in-non-instantiated-generic.rs +++ b/src/test/codegen-units/impl-in-non-instantiated-generic.rs @@ -21,7 +21,7 @@ trait SomeTrait { // discovered. pub fn generic_function(x: T) -> (T, i32) { impl SomeTrait for i64 { - //~ TRANS_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::i64.SomeTrait[0]::foo[0] + //~ TRANS_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::{{impl}}[0]::foo[0] fn foo(&self) {} } diff --git a/src/test/codegen-units/instantiation-through-vtable.rs b/src/test/codegen-units/instantiation-through-vtable.rs index 46587b2b0a1b2..b772525122001 100644 --- a/src/test/codegen-units/instantiation-through-vtable.rs +++ b/src/test/codegen-units/instantiation-through-vtable.rs @@ -31,12 +31,12 @@ impl Trait for Struct { fn main() { let s1 = Struct { _a: 0u32 }; - //~ TRANS_ITEM fn instantiation_through_vtable::Struct.Trait[0]::foo[0] - //~ TRANS_ITEM fn instantiation_through_vtable::Struct.Trait[0]::bar[0] + //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] + //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; let s1 = Struct { _a: 0u64 }; - //~ TRANS_ITEM fn instantiation_through_vtable::Struct.Trait[0]::foo[0] - //~ TRANS_ITEM fn instantiation_through_vtable::Struct.Trait[0]::bar[0] + //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] + //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; } diff --git a/src/test/codegen-units/non-generic-drop-glue.rs b/src/test/codegen-units/non-generic-drop-glue.rs index a82e85b7a5315..bd8b0c605aecf 100644 --- a/src/test/codegen-units/non-generic-drop-glue.rs +++ b/src/test/codegen-units/non-generic-drop-glue.rs @@ -19,7 +19,7 @@ struct StructWithDrop { } impl Drop for StructWithDrop { - //~ TRANS_ITEM fn non_generic_drop_glue::StructWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn non_generic_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } @@ -33,7 +33,7 @@ enum EnumWithDrop { } impl Drop for EnumWithDrop { - //~ TRANS_ITEM fn non_generic_drop_glue::EnumWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn non_generic_drop_glue::{{impl}}[1]::drop[0] fn drop(&mut self) {} } diff --git a/src/test/codegen-units/non-generic-functions.rs b/src/test/codegen-units/non-generic-functions.rs index 687ce7fa05cb4..4e2a7c8508468 100644 --- a/src/test/codegen-units/non-generic-functions.rs +++ b/src/test/codegen-units/non-generic-functions.rs @@ -38,31 +38,31 @@ fn bar() { struct Struct { _x: i32 } impl Struct { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0] fn foo() { { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]::foo[0] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[0] fn foo() {} foo(); } { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]::foo[1] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[1] fn foo() {} foo(); } } - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0] fn bar(&self) { { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]::foo[0] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[0] fn foo() {} foo(); } { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]::foo[1] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[1] fn foo() {} foo(); } diff --git a/src/test/codegen-units/overloaded-operators.rs b/src/test/codegen-units/overloaded-operators.rs index 134110222f392..c275eb954b094 100644 --- a/src/test/codegen-units/overloaded-operators.rs +++ b/src/test/codegen-units/overloaded-operators.rs @@ -23,7 +23,7 @@ pub struct Indexable { impl Index for Indexable { type Output = u8; - //~ TRANS_ITEM fn overloaded_operators::Indexable.Index[0]::index[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[0]::index[0] fn index(&self, index: usize) -> &Self::Output { if index >= 3 { &self.data[0] @@ -34,7 +34,7 @@ impl Index for Indexable { } impl IndexMut for Indexable { - //~ TRANS_ITEM fn overloaded_operators::Indexable.IndexMut[0]::index_mut[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[1]::index_mut[0] fn index_mut(&mut self, index: usize) -> &mut Self::Output { if index >= 3 { &mut self.data[0] @@ -45,8 +45,8 @@ impl IndexMut for Indexable { } -//~ TRANS_ITEM fn overloaded_operators::Equatable.::std::cmp::PartialEq[0]::eq[0] -//~ TRANS_ITEM fn overloaded_operators::Equatable.::std::cmp::PartialEq[0]::ne[0] +//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::eq[0] +//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::ne[0] #[derive(PartialEq)] pub struct Equatable(u32); @@ -54,7 +54,7 @@ pub struct Equatable(u32); impl Add for Equatable { type Output = u32; - //~ TRANS_ITEM fn overloaded_operators::Equatable.Add[0]::add[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::add[0] fn add(self, rhs: u32) -> u32 { self.0 + rhs } @@ -63,7 +63,7 @@ impl Add for Equatable { impl Deref for Equatable { type Target = u32; - //~ TRANS_ITEM fn overloaded_operators::Equatable.Deref[0]::deref[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::deref[0] fn deref(&self) -> &Self::Target { &self.0 } diff --git a/src/test/codegen-units/trait-implementations.rs b/src/test/codegen-units/trait-implementations.rs index 590859f15a3e1..2eb2212f0cacd 100644 --- a/src/test/codegen-units/trait-implementations.rs +++ b/src/test/codegen-units/trait-implementations.rs @@ -20,7 +20,7 @@ pub trait SomeTrait { impl SomeTrait for i64 { - //~ TRANS_ITEM fn trait_implementations::i64.SomeTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[0]::foo[0] fn foo(&self) {} fn bar(&self, _: T) {} @@ -28,7 +28,7 @@ impl SomeTrait for i64 { impl SomeTrait for i32 { - //~ TRANS_ITEM fn trait_implementations::i32.SomeTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::foo[0] fn foo(&self) {} fn bar(&self, _: T) {} @@ -42,7 +42,7 @@ pub trait SomeGenericTrait { // Concrete impl of generic trait impl SomeGenericTrait for f64 { - //~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::foo[0] fn foo(&self, _: u32) {} fn bar(&self, _: u32, _: T2) {} @@ -57,25 +57,25 @@ impl SomeGenericTrait for f32 { //~ TRANS_ITEM fn trait_implementations::main[0] fn main() { - //~ TRANS_ITEM fn trait_implementations::i32.SomeTrait[0]::bar[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::bar[0] 0i32.bar('x'); - //~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait[0]::bar[0]<&str> + //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<&str> 0f64.bar(0u32, "&str"); - //~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait[0]::bar[0]<()> + //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<()> 0f64.bar(0u32, ()); - //~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::foo[0] 0f32.foo('x'); - //~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::foo[0] 0f32.foo(-1i64); - //~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait[0]::bar[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0] 0f32.bar(0u32, ()); - //~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait[0]::bar[0]<&str, &str> + //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str> 0f32.bar("&str", "&str"); } diff --git a/src/test/codegen-units/trait-method-as-argument.rs b/src/test/codegen-units/trait-method-as-argument.rs index fdf63df547111..e7006d73ef166 100644 --- a/src/test/codegen-units/trait-method-as-argument.rs +++ b/src/test/codegen-units/trait-method-as-argument.rs @@ -39,7 +39,7 @@ fn take_foo_mut T>(mut f: F, arg: T) -> T { //~ TRANS_ITEM fn trait_method_as_argument::main[0] fn main() { //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] u32> - //~ TRANS_ITEM fn trait_method_as_argument::u32.Trait[0]::foo[0] + //~ TRANS_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0] take_foo_once(Trait::foo, 0u32); //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] char> diff --git a/src/test/codegen-units/transitive-drop-glue.rs b/src/test/codegen-units/transitive-drop-glue.rs index 6982cb9299a55..21bb29199a685 100644 --- a/src/test/codegen-units/transitive-drop-glue.rs +++ b/src/test/codegen-units/transitive-drop-glue.rs @@ -21,7 +21,7 @@ struct Intermediate(Leaf); struct Leaf; impl Drop for Leaf { - //~ TRANS_ITEM fn transitive_drop_glue::Leaf.Drop[0]::drop[0] + //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } @@ -44,12 +44,12 @@ fn main() { //~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0] //~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0] //~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0] - //~ TRANS_ITEM fn transitive_drop_glue::LeafGen.Drop[0]::drop[0] + //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0u32))); //~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0] //~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0] //~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0] - //~ TRANS_ITEM fn transitive_drop_glue::LeafGen.Drop[0]::drop[0] + //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0i16))); } diff --git a/src/test/codegen-units/tuple-drop-glue.rs b/src/test/codegen-units/tuple-drop-glue.rs index 87fcb00eab8c2..1bc235de88e1f 100644 --- a/src/test/codegen-units/tuple-drop-glue.rs +++ b/src/test/codegen-units/tuple-drop-glue.rs @@ -17,7 +17,7 @@ struct Dropped; impl Drop for Dropped { - //~ TRANS_ITEM fn tuple_drop_glue::Dropped.Drop[0]::drop[0] + //~ TRANS_ITEM fn tuple_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } diff --git a/src/test/codegen-units/unsizing.rs b/src/test/codegen-units/unsizing.rs index dd90d32858f11..45ba441bc8ba6 100644 --- a/src/test/codegen-units/unsizing.rs +++ b/src/test/codegen-units/unsizing.rs @@ -57,11 +57,11 @@ fn main() { // simple case let bool_sized = &true; - //~ TRANS_ITEM fn unsizing::bool.Trait[0]::foo[0] + //~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0] let _bool_unsized = bool_sized as &Trait; let char_sized = &true; - //~ TRANS_ITEM fn unsizing::char.Trait[0]::foo[0] + //~ TRANS_ITEM fn unsizing::{{impl}}[1]::foo[0] let _char_unsized = char_sized as &Trait; // struct field @@ -70,11 +70,11 @@ fn main() _b: 2, _c: 3.0f64 }; - //~ TRANS_ITEM fn unsizing::f64.Trait[0]::foo[0] + //~ TRANS_ITEM fn unsizing::{{impl}}[2]::foo[0] let _struct_unsized = struct_sized as &Struct; // custom coercion let wrapper_sized = Wrapper(&0u32); - //~ TRANS_ITEM fn unsizing::u32.Trait[0]::foo[0] + //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; } diff --git a/src/test/codegen-units/unused-traits-and-generics.rs b/src/test/codegen-units/unused-traits-and-generics.rs index a4c5099ab9751..8689beb3fb77e 100644 --- a/src/test/codegen-units/unused-traits-and-generics.rs +++ b/src/test/codegen-units/unused-traits-and-generics.rs @@ -85,5 +85,5 @@ impl NonGeneric { } // Only the non-generic methods should be instantiated: -//~ TRANS_ITEM fn unused_traits_and_generics::NonGeneric[0]::foo[0] +//~ TRANS_ITEM fn unused_traits_and_generics::{{impl}}[3]::foo[0] //~ TRANS_ITEM drop-glue i8 diff --git a/src/test/compile-fail/symbol-names/basic.rs b/src/test/compile-fail/symbol-names/basic.rs new file mode 100644 index 0000000000000..0095774fcb8d2 --- /dev/null +++ b/src/test/compile-fail/symbol-names/basic.rs @@ -0,0 +1,16 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +#[rustc_symbol_name] //~ ERROR _ZN5basic4main +#[rustc_item_path] //~ ERROR item-path(main) +fn main() { +} diff --git a/src/test/compile-fail/symbol-names/impl1.rs b/src/test/compile-fail/symbol-names/impl1.rs new file mode 100644 index 0000000000000..39bee26da20b8 --- /dev/null +++ b/src/test/compile-fail/symbol-names/impl1.rs @@ -0,0 +1,35 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod foo { + pub struct Foo { x: u32 } + + impl Foo { + #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar + #[rustc_item_path] //~ ERROR item-path(foo::Foo::bar) + fn bar() { } + } +} + +mod bar { + use foo::Foo; + + impl Foo { + #[rustc_symbol_name] //~ ERROR _ZN5impl13bar26_$LT$impl$u20$foo..Foo$GT$3baz + #[rustc_item_path] //~ ERROR item-path(bar::::baz) + fn baz() { } + } +} + +fn main() { +} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index fedb68a26afc9..fe4337eedc63d 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -41,37 +41,37 @@ ((::std::fmt::format as fn(core::fmt::Arguments<'_>) -> collections::string::String {collections::fmt::format})(((::std::fmt::Arguments::new_v1 as - fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a><'_>::new_v1})(({ - static __STATIC_FMTSTR: - &'static [&'static str] - = - (&([("test" - as - &'static str)] - as - [&'static str; 1]) + fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'_>::new_v1})(({ + static __STATIC_FMTSTR: + &'static [&'static str] + = + (&([("test" as - &'static [&'static str; 1]); - (__STATIC_FMTSTR - as - &'static [&'static str]) - } - as - &[&str]), - (&(match (() - as - ()) - { - () - => - ([] + &'static str)] as - [core::fmt::ArgumentV1<'_>; 0]), - } - as - [core::fmt::ArgumentV1<'_>; 0]) - as - &[core::fmt::ArgumentV1<'_>; 0])) + [&'static str; 1]) + as + &'static [&'static str; 1]); + (__STATIC_FMTSTR + as + &'static [&'static str]) + } + as + &[&str]), + (&(match (() + as + ()) + { + () + => + ([] + as + [core::fmt::ArgumentV1<'_>; 0]), + } + as + [core::fmt::ArgumentV1<'_>; 0]) + as + &[core::fmt::ArgumentV1<'_>; 0])) as core::fmt::Arguments<'_>)) as collections::string::String); diff --git a/src/test/run-make/a-b-a-linker-guard/Makefile b/src/test/run-make/a-b-a-linker-guard/Makefile new file mode 100644 index 0000000000000..0962ebfbff546 --- /dev/null +++ b/src/test/run-make/a-b-a-linker-guard/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +# Test that if we build `b` against a version of `a` that has one set +# of types, it will not run with a dylib that has a different set of +# types. + +all: + $(RUSTC) a.rs --cfg x -C prefer-dynamic + $(RUSTC) b.rs -C prefer-dynamic + $(call RUN,b) + $(RUSTC) a.rs --cfg y -C prefer-dynamic + $(call FAIL,b) diff --git a/src/test/run-make/a-b-a-linker-guard/a.rs b/src/test/run-make/a-b-a-linker-guard/a.rs new file mode 100644 index 0000000000000..e6cbe2e64d0e9 --- /dev/null +++ b/src/test/run-make/a-b-a-linker-guard/a.rs @@ -0,0 +1,20 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "a"] +#![crate_type = "dylib"] + +#[cfg(x)] +pub fn foo(x: u32) { } + +#[cfg(y)] +pub fn foo(x: i32) { } + + diff --git a/src/test/run-make/a-b-a-linker-guard/b.rs b/src/test/run-make/a-b-a-linker-guard/b.rs new file mode 100644 index 0000000000000..89fd48de5bbf9 --- /dev/null +++ b/src/test/run-make/a-b-a-linker-guard/b.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "b"] + +extern crate a; + +fn main() { + a::foo(22_u32); +} diff --git a/src/test/run-make/extern-overrides-distribution/Makefile b/src/test/run-make/extern-overrides-distribution/Makefile index 110db9f068dae..7d063a4c83cba 100644 --- a/src/test/run-make/extern-overrides-distribution/Makefile +++ b/src/test/run-make/extern-overrides-distribution/Makefile @@ -1,5 +1,5 @@ -include ../tools.mk all: - $(RUSTC) libc.rs + $(RUSTC) libc.rs -Cmetadata=foo $(RUSTC) main.rs --extern libc=$(TMPDIR)/liblibc.rlib diff --git a/src/test/run-make/issue-26006/Makefile b/src/test/run-make/issue-26006/Makefile index de89a6f6ad692..66aa78d538637 100644 --- a/src/test/run-make/issue-26006/Makefile +++ b/src/test/run-make/issue-26006/Makefile @@ -12,7 +12,7 @@ time: libc libc: mkdir -p $(OUT)/libc - $(RUSTC) in/libc/lib.rs --crate-name=libc -o $(OUT)/libc/liblibc.rlib + $(RUSTC) in/libc/lib.rs --crate-name=libc -Cmetadata=foo -o $(OUT)/libc/liblibc.rlib else all: endif diff --git a/src/test/run-make/link-guard/Makefile b/src/test/run-make/link-guard/Makefile new file mode 100644 index 0000000000000..38970652cb580 --- /dev/null +++ b/src/test/run-make/link-guard/Makefile @@ -0,0 +1,13 @@ +-include ../tools.mk + +all: + -mkdir -p $(TMPDIR)/good + -mkdir -p $(TMPDIR)/bad + $(BARE_RUSTC) ./good/lib.rs -C prefer-dynamic --out-dir="$(TMPDIR)/good" + $(BARE_RUSTC) ./bad/lib.rs -C prefer-dynamic --out-dir="$(TMPDIR)/bad" + $(BARE_RUSTC) -L "$(TMPDIR)/good" -C prefer-dynamic -Crpath ./main.rs --out-dir="$(TMPDIR)" + # This should succeed because the correct library is in LD_LIBRARY_PATH + $(LD_LIB_PATH_ENVVAR)="$(TMPDIR)/good:$($(LD_LIB_PATH_ENVVAR))" $(TMPDIR)/main + # This should fail because the wrong library is in LD_LIBRARY_PATH + OUTPUT=`$(LD_LIB_PATH_ENVVAR)="$(TMPDIR)/bad:$($(LD_LIB_PATH_ENVVAR))" $(TMPDIR)/main || exit 0` + if ["$(OUTPUT)" == "bad"]; then exit 1; fi diff --git a/src/test/run-make/link-guard/bad/lib.rs b/src/test/run-make/link-guard/bad/lib.rs new file mode 100644 index 0000000000000..c13c0d5e92f91 --- /dev/null +++ b/src/test/run-make/link-guard/bad/lib.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name="thelibrary"] +#![crate_type="dylib"] + +pub fn some_library_function() { + println!("bad"); +} diff --git a/src/test/run-make/link-guard/good/lib.rs b/src/test/run-make/link-guard/good/lib.rs new file mode 100644 index 0000000000000..c13c0d5e92f91 --- /dev/null +++ b/src/test/run-make/link-guard/good/lib.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name="thelibrary"] +#![crate_type="dylib"] + +pub fn some_library_function() { + println!("bad"); +} diff --git a/src/test/run-make/link-guard/main.rs b/src/test/run-make/link-guard/main.rs new file mode 100644 index 0000000000000..c422316d9183d --- /dev/null +++ b/src/test/run-make/link-guard/main.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate thelibrary; + +fn main() { + thelibrary::some_library_function(); +} diff --git a/src/test/run-make/relocation-model/Makefile b/src/test/run-make/relocation-model/Makefile index b22f34fa35b54..485ecbb4b5a59 100644 --- a/src/test/run-make/relocation-model/Makefile +++ b/src/test/run-make/relocation-model/Makefile @@ -7,8 +7,7 @@ all: others $(RUSTC) -C relocation-model=default foo.rs $(call RUN,foo) - $(RUSTC) -C relocation-model=default --crate-type=dylib foo.rs - $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs + $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs --emit=link,obj ifdef IS_MSVC # FIXME(#28026) @@ -17,5 +16,4 @@ else others: $(RUSTC) -C relocation-model=static foo.rs $(call RUN,foo) - $(RUSTC) -C relocation-model=static --crate-type=dylib foo.rs endif diff --git a/src/test/run-make/reproducible-build/Makefile b/src/test/run-make/reproducible-build/Makefile new file mode 100644 index 0000000000000..8e799ca1a4303 --- /dev/null +++ b/src/test/run-make/reproducible-build/Makefile @@ -0,0 +1,20 @@ +-include ../tools.mk +all: + $(RUSTC) reproducible-build-aux.rs + $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build1" + $(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build2" + nm "$(TMPDIR)/reproducible-build1" | sort > "$(TMPDIR)/reproducible-build1.nm" + nm "$(TMPDIR)/reproducible-build2" | sort > "$(TMPDIR)/reproducible-build2.nm" + cmp "$(TMPDIR)/reproducible-build1.nm" "$(TMPDIR)/reproducible-build2.nm" || exit 1 + $(RUSTC) reproducible-build-aux.rs -g + $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build1-debug" + $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build2-debug" + nm "$(TMPDIR)/reproducible-build1-debug" | sort > "$(TMPDIR)/reproducible-build1-debug.nm" + nm "$(TMPDIR)/reproducible-build2-debug" | sort > "$(TMPDIR)/reproducible-build2-debug.nm" + cmp "$(TMPDIR)/reproducible-build1-debug.nm" "$(TMPDIR)/reproducible-build2-debug.nm" || exit 1 + $(RUSTC) reproducible-build-aux.rs -O + $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build1-opt" + $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build2-opt" + nm "$(TMPDIR)/reproducible-build1-opt" | sort > "$(TMPDIR)/reproducible-build1-opt.nm" + nm "$(TMPDIR)/reproducible-build2-opt" | sort > "$(TMPDIR)/reproducible-build2-opt.nm" + cmp "$(TMPDIR)/reproducible-build1-opt.nm" "$(TMPDIR)/reproducible-build2-opt.nm" || exit 1 diff --git a/src/test/run-make/reproducible-build/reproducible-build-aux.rs b/src/test/run-make/reproducible-build/reproducible-build-aux.rs new file mode 100644 index 0000000000000..9ef853e79960b --- /dev/null +++ b/src/test/run-make/reproducible-build/reproducible-build-aux.rs @@ -0,0 +1,38 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="lib"] + +pub static STATIC: i32 = 1234; + +pub struct Struct { + _t1: std::marker::PhantomData, + _t2: std::marker::PhantomData, +} + +pub fn regular_fn(_: i32) {} + +pub fn generic_fn() {} + +impl Drop for Struct { + fn drop(&mut self) {} +} + +pub enum Enum { + Variant1, + Variant2(u32), + Variant3 { x: u32 } +} + +pub struct TupleStruct(pub i8, pub i16, pub i32, pub i64); + +pub trait Trait { + fn foo(&self); +} diff --git a/src/test/run-make/reproducible-build/reproducible-build.rs b/src/test/run-make/reproducible-build/reproducible-build.rs new file mode 100644 index 0000000000000..dc7c702e5cc67 --- /dev/null +++ b/src/test/run-make/reproducible-build/reproducible-build.rs @@ -0,0 +1,128 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test case makes sure that two identical invocations of the compiler +// (i.e. same code base, same compile-flags, same compiler-versions, etc.) +// produce the same output. In the past, symbol names of monomorphized functions +// were not deterministic (which we want to avoid). +// +// The test tries to exercise as many different paths into symbol name +// generation as possible: +// +// - regular functions +// - generic functions +// - methods +// - statics +// - closures +// - enum variant constructors +// - tuple struct constructors +// - drop glue +// - FnOnce adapters +// - Trait object shims +// - Fn Pointer shims + +#![allow(dead_code)] + +extern crate reproducible_build_aux; + +static STATIC: i32 = 1234; + +pub struct Struct { + x: T1, + y: T2, +} + +fn regular_fn(_: i32) {} + +fn generic_fn() {} + +impl Drop for Struct { + fn drop(&mut self) {} +} + +pub enum Enum { + Variant1, + Variant2(u32), + Variant3 { x: u32 } +} + +struct TupleStruct(i8, i16, i32, i64); + +impl TupleStruct { + pub fn bar(&self) {} +} + +trait Trait { + fn foo(&self); +} + +impl Trait for u64 { + fn foo(&self) {} +} + +impl reproducible_build_aux::Trait for TupleStruct { + fn foo(&self) {} +} + +fn main() { + regular_fn(STATIC); + generic_fn::(); + generic_fn::>(); + generic_fn::, reproducible_build_aux::Struct>(); + + let dropped = Struct { + x: "", + y: 'a', + }; + + let _ = Enum::Variant1; + let _ = Enum::Variant2(0); + let _ = Enum::Variant3 { x: 0 }; + let _ = TupleStruct(1, 2, 3, 4); + + let closure = |x| { + x + 1i32 + }; + + fn inner i32>(f: F) -> i32 { + f(STATIC) + } + + println!("{}", inner(closure)); + + let object_shim: &Trait = &0u64; + object_shim.foo(); + + fn with_fn_once_adapter(f: F) { + f(0); + } + + with_fn_once_adapter(|_:i32| { }); + + reproducible_build_aux::regular_fn(STATIC); + reproducible_build_aux::generic_fn::(); + reproducible_build_aux::generic_fn::>(); + reproducible_build_aux::generic_fn::, + reproducible_build_aux::Struct>(); + + let _ = reproducible_build_aux::Enum::Variant1; + let _ = reproducible_build_aux::Enum::Variant2(0); + let _ = reproducible_build_aux::Enum::Variant3 { x: 0 }; + let _ = reproducible_build_aux::TupleStruct(1, 2, 3, 4); + + let object_shim: &reproducible_build_aux::Trait = &TupleStruct(0, 1, 2, 3); + object_shim.foo(); + + let pointer_shim: &Fn(i32) = ®ular_fn; + + TupleStruct(1, 2, 3, 4).bar(); +} + + diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 2a98706351a8b..75f057e1e1d8f 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -51,13 +51,30 @@ fn template(me: &str) -> Command { return m; } +fn expected(fn_name: &str) -> String { + // FIXME(#32481) + // + // On windows, we read the function name from debuginfo using some + // system APIs. For whatever reason, these APIs seem to use the + // "name" field, which is only the "relative" name, not the full + // name with namespace info, so we just see `foo` and not + // `backtrace::foo` as we see on linux (which uses the linkage + // name). + + if cfg!(windows) { + format!(" - {}", fn_name) + } else { + format!(" - backtrace::{}", fn_name) + } +} + fn runtest(me: &str) { // Make sure that the stack trace is printed let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); let s = str::from_utf8(&out.stderr).unwrap(); - assert!(s.contains("stack backtrace") && s.contains(" - foo"), + assert!(s.contains("stack backtrace") && s.contains(&expected("foo")), "bad output: {}", s); // Make sure the stack trace is *not* printed @@ -67,7 +84,7 @@ fn runtest(me: &str) { let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); let s = str::from_utf8(&out.stderr).unwrap(); - assert!(!s.contains("stack backtrace") && !s.contains(" - foo"), + assert!(!s.contains("stack backtrace") && !s.contains(&expected("foo")), "bad output2: {}", s); // Make sure a stack trace is printed @@ -77,7 +94,7 @@ fn runtest(me: &str) { let s = str::from_utf8(&out.stderr).unwrap(); // loosened the following from double::h to double:: due to // spurious failures on mac, 32bit, optimized - assert!(s.contains("stack backtrace") && s.contains(" - double"), + assert!(s.contains("stack backtrace") && s.contains(&expected("double")), "bad output3: {}", s); // Make sure a stack trace isn't printed too many times diff --git a/src/test/run-pass/command-before-exec.rs b/src/test/run-pass/command-before-exec.rs index 7c5a21911dbfb..16560637b6926 100644 --- a/src/test/run-pass/command-before-exec.rs +++ b/src/test/run-pass/command-before-exec.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-windows - this is a unix-specific test -// no-prefer-dynamic - this test breaks with dynamic linking as -// some LD_LIBRARY_PATH entries are relative and it cd's to /. #![feature(process_exec, libc)] diff --git a/src/test/run-pass/issue-17718.rs b/src/test/run-pass/issue-17718.rs index 2bb69d105ff5d..744e63f159b65 100644 --- a/src/test/run-pass/issue-17718.rs +++ b/src/test/run-pass/issue-17718.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:issue-17718.rs +// aux-build:issue-17718-aux.rs #![feature(core)] #![feature(const_fn)] -extern crate issue_17718 as other; +extern crate issue_17718_aux as other; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index db53fa855f11d..4bd82baafeb10 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:typeid-intrinsic.rs -// aux-build:typeid-intrinsic2.rs +// aux-build:typeid-intrinsic-aux1.rs +// aux-build:typeid-intrinsic-aux2.rs #![feature(core_intrinsics)] -extern crate typeid_intrinsic as other1; -extern crate typeid_intrinsic2 as other2; +extern crate typeid_intrinsic_aux1 as other1; +extern crate typeid_intrinsic_aux2 as other2; use std::hash::{SipHasher, Hasher, Hash}; use std::any::TypeId;