From 1dae394f2716e3d2894a8695eba1db6a9c43d17b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 10 Feb 2016 10:04:45 -0500 Subject: [PATCH 01/18] CrateStore: Allow for custom def_id_to_string mappings in encode_type(). --- src/librustc/middle/cstore.rs | 15 ++++++++++++--- src/librustc_metadata/csearch.rs | 8 ++++++-- src/librustc_metadata/encoder.rs | 9 ++++++--- src/librustc_metadata/tyencode.rs | 22 +++++++++++----------- src/librustc_trans/back/link.rs | 6 +++++- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 6a4680ecbaf31..b20a18aa5c8e0 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -236,7 +236,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; @@ -419,8 +423,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_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 2cd119cfc48be..c277e9006fbc5 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -480,9 +480,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/encoder.rs b/src/librustc_metadata/encoder.rs index 41baa0b159148..ff3a9ba0c43bf 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -158,7 +158,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()) } @@ -2125,11 +2125,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/tyencode.rs b/src/librustc_metadata/tyencode.rs index a6601e591ab67..e298c621a637e 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); @@ -322,7 +322,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) => { @@ -336,7 +336,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); } @@ -420,8 +420,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); } @@ -429,7 +429,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"); @@ -489,7 +489,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_trans/back/link.rs b/src/librustc_trans/back/link.rs index 88ae6cb91abb4..fd9d8e7423087 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -22,6 +22,7 @@ use session::search_paths::PathKind; use session::Session; use middle::cstore::{self, CrateStore, LinkMeta}; use middle::cstore::{LinkagePreference, NativeLibraryKind}; +use middle::def_id::DefId; use middle::dependency_format::Linkage; use middle::ty::{Ty, TyCtxt}; use rustc::front::map::DefPath; @@ -200,6 +201,9 @@ fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String { output[.. 8].to_hex().to_string() } +pub fn def_to_string(_tcx: &ty::ctxt, did: DefId) -> String { + format!("{}:{}", did.krate, did.index.as_usize()) +} // This calculates STH for a symbol, as defined above fn symbol_hash<'tcx>(tcx: &TyCtxt<'tcx>, @@ -218,7 +222,7 @@ fn symbol_hash<'tcx>(tcx: &TyCtxt<'tcx>, symbol_hasher.input_str(&meta[..]); } symbol_hasher.input_str("-"); - symbol_hasher.input(&tcx.sess.cstore.encode_type(tcx, t)); + symbol_hasher.input(&tcx.sess.cstore.encode_type(tcx, t, def_to_string)); // 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)); From d4b55d206386018ea66af1d38543329f57642588 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sat, 13 Feb 2016 12:55:04 -0500 Subject: [PATCH 02/18] Add missing entries for enum variants in trans::CrateContext::external_srcs. --- src/librustc_trans/trans/inline.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 4c647152458f4..d95a7668342cb 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -106,6 +106,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, _) => { @@ -114,6 +115,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(); } } From 95c0daffee2876b24bf6c10a5e2dee0aa9fee34a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 12 Feb 2016 12:43:13 -0500 Subject: [PATCH 03/18] Make CrateStore::crate_name() return an InternedString to avoid unnecessary allocations. --- src/librustc/middle/cstore.rs | 5 +++-- src/librustc_metadata/csearch.rs | 4 ++-- src/librustc_trans/save/mod.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b20a18aa5c8e0..f8d2edeaa2c76 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; @@ -203,7 +204,7 @@ pub trait CrateStore<'tcx> : Any { fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; fn is_allocator(&self, cnum: ast::CrateNum) -> bool; fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; - fn crate_name(&self, cnum: ast::CrateNum) -> String; + fn crate_name(&self, cnum: ast::CrateNum) -> InternedString; fn crate_hash(&self, cnum: ast::CrateNum) -> Svh; fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) -> FnvHashMap>; @@ -382,7 +383,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_allocator(&self, cnum: ast::CrateNum) -> bool { 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 crate_hash(&self, cnum: ast::CrateNum) -> Svh { unimplemented!() } fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) -> FnvHashMap> diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index c277e9006fbc5..c0de55519918b 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -335,9 +335,9 @@ 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 { - self.get_crate_data(cnum).name.clone() + token::intern_and_get_ident(&self.get_crate_data(cnum).name[..]) } fn crate_hash(&self, cnum: ast::CrateNum) -> Svh diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 7f9f876fad1fa..4038882ceb8df 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -219,7 +219,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/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 54821bd1161ee..64a7daecb95d6 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, } From 410caeb97d9ee4aa89f7be13967ef73f6e902126 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Feb 2016 08:44:06 -0500 Subject: [PATCH 04/18] Make library paths passed by compiletest tool absolute. Otherwise, changing the current working directory can mess up runtime linking. --- src/compiletest/common.rs | 4 ++-- src/compiletest/compiletest.rs | 18 ++++++++++++++++-- src/compiletest/runtest.rs | 10 +++++----- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index e66094dc3954b..4084a4e8e03e9 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 458a3a8c739f4..b566afae56c21 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -116,9 +116,23 @@ 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 + } + } + + let filter = if !matches.free.is_empty() { + Some(matches.free[0].clone()) + } else { + None + }; + 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 8c3ee3fb5f4b6..9a7025bbbe5aa 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); } @@ -1292,7 +1292,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) } @@ -1364,7 +1364,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() { @@ -1387,7 +1387,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, testpaths, args, Vec::new(), - &config.compile_lib_path, + config.compile_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), input) } From 446d4ecb45e2c92ef56e24423ad86ff980ea7e87 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 12 Feb 2016 08:41:30 -0500 Subject: [PATCH 05/18] Compute a salt from arguments passed via -Cmetadata. --- src/librbml/lib.rs | 4 ++-- src/librustc/middle/cstore.rs | 2 ++ src/librustc/session/mod.rs | 9 +++++++-- src/librustc_back/svh.rs | 8 ++++---- src/librustc_driver/driver.rs | 33 +++++++++++++++++++++++++++++--- src/librustc_driver/lib.rs | 2 -- src/librustc_metadata/common.rs | 1 + src/librustc_metadata/csearch.rs | 6 ++++++ src/librustc_metadata/decoder.rs | 7 +++++++ src/librustc_metadata/encoder.rs | 5 +++++ src/librustc_trans/back/link.rs | 8 +++----- 11 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 533f2ee3b3e61..aba92473aac4f 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -165,7 +165,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) } @@ -173,7 +173,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/middle/cstore.rs b/src/librustc/middle/cstore.rs index f8d2edeaa2c76..144e3afdeb38c 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -206,6 +206,7 @@ pub trait CrateStore<'tcx> : Any { fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; fn 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; @@ -385,6 +386,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { { unimplemented!() } fn 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!() } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index b198eda181208..36dc8eabc89f2 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -64,7 +64,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: RefCell, pub features: RefCell, /// The maximum recursion limit for potentially infinitely recursive @@ -481,7 +486,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: RefCell::new(String::new()), 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 b01b80b813399..b1bef74251e70 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 8dac25cc0cbf1..7677013ea6871 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.borrow_mut() = compute_crate_disambiguator(sess); time(time_passes, "recursion limit", || { middle::recursion_limit::update_recursion_limit(sess, &krate); @@ -1121,8 +1122,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 357c7238c1f6c..b6cfc2ec20bc6 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -567,8 +567,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_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/csearch.rs b/src/librustc_metadata/csearch.rs index c0de55519918b..e47a14ba7f716 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -346,6 +346,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> { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 38a2a7794bcbd..1fe221348fc2e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1318,6 +1318,13 @@ pub fn maybe_get_crate_name(data: &[u8]) -> Option { }) } +pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str { + let crate_doc = rbml::Doc::new(data); + let salt_doc = reader::get_doc(crate_doc, tag_crate_disambiguator); + let slice: &'a str = salt_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); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ff3a9ba0c43bf..f1cf616beb802 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1899,6 +1899,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); } @@ -2034,6 +2038,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.borrow()); encode_dylib_dependency_formats(rbml_w, &ecx); let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index fd9d8e7423087..c6c1180c76637 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -189,7 +189,7 @@ 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.borrow()[..], krate), }; info!("{:?}", r); return r; @@ -201,7 +201,7 @@ fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String { output[.. 8].to_hex().to_string() } -pub fn def_to_string(_tcx: &ty::ctxt, did: DefId) -> String { +pub fn def_to_string(_tcx: &TyCtxt, did: DefId) -> String { format!("{}:{}", did.krate, did.index.as_usize()) } @@ -218,9 +218,7 @@ fn symbol_hash<'tcx>(tcx: &TyCtxt<'tcx>, 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(&tcx.sess.crate_disambiguator.borrow()[..]); symbol_hasher.input_str("-"); symbol_hasher.input(&tcx.sess.cstore.encode_type(tcx, t, def_to_string)); // Prefix with 'h' so that it never blends into adjacent digits From b2eed71ba7fe38578a8b1b2cd6fcc30f37fc8d6f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 12:30:38 -0500 Subject: [PATCH 06/18] Make the definite name of the local crate available in the tcx. --- src/librustc/middle/ty/context.rs | 10 ++++++++-- src/librustc_driver/driver.rs | 1 + src/librustc_driver/test.rs | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 03c13115aea62..4e81297a789a8 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -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,6 +415,10 @@ 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> { @@ -511,6 +515,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 +575,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_driver/driver.rs b/src/librustc_driver/driver.rs index 7677013ea6871..b8b2d39fe5d76 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -818,6 +818,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)); 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, From b5a7fd9600bec4cbbb9be82e30c1d616813478e0 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 13:01:44 -0500 Subject: [PATCH 07/18] Make monomorphized functions use stable symbol names. --- src/librustc_trans/back/symbol_names.rs | 224 ++++++++++++++++++ src/librustc_trans/lib.rs | 1 + src/librustc_trans/trans/base.rs | 3 +- src/librustc_trans/trans/foreign.rs | 22 +- src/librustc_trans/trans/monomorphize.rs | 44 ++-- ...-intrinsic.rs => typeid-intrinsic-aux1.rs} | 0 ...intrinsic2.rs => typeid-intrinsic-aux2.rs} | 0 src/test/compile-fail/dupe-symbols-8.rs | 23 -- src/test/run-pass/typeid-intrinsic.rs | 8 +- 9 files changed, 258 insertions(+), 67 deletions(-) create mode 100644 src/librustc_trans/back/symbol_names.rs rename src/test/auxiliary/{typeid-intrinsic.rs => typeid-intrinsic-aux1.rs} (100%) rename src/test/auxiliary/{typeid-intrinsic2.rs => typeid-intrinsic-aux2.rs} (100%) delete mode 100644 src/test/compile-fail/dupe-symbols-8.rs diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs new file mode 100644 index 0000000000000..f95bbfbe0a7b6 --- /dev/null +++ b/src/librustc_trans/back/symbol_names.rs @@ -0,0 +1,224 @@ +// 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 "salt" value via the +//! `-C metadata` commandline argument. This salt is then fed into the symbol +//! hash of every exported item. Consequently, the symbols in two identical +//! crates but with different salts 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; +use util::sha2::{Digest, Sha256}; + +use rustc::middle::cstore; +use rustc::middle::def_id::DefId; +use rustc::middle::ty::{self, TypeFoldable}; +use rustc::front::map::definitions::DefPath; + +use std::fmt::Write; +use syntax::ast; +use syntax::parse::token; +use serialize::hex::ToHex; +use super::link; + +pub fn def_id_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_id: DefId) -> String { + + let def_path = tcx.def_path(def_id); + let mut s = String::with_capacity(def_path.len() * 16); + + let def_path = if def_id.is_local() { + s.push_str(&tcx.crate_name[..]); + s.push_str("/"); + s.push_str(&tcx.sess.crate_salt.borrow()[..]); + &def_path[..] + } else { + s.push_str(&tcx.sess.cstore.crate_name(def_id.krate)[..]); + s.push_str("/"); + s.push_str(&tcx.sess.cstore.crate_salt(def_id.krate)); + &def_path[1..] + }; + + for component in def_path { + write!(s, + "::{}[{}]", + component.data.as_interned_str(), + component.disambiguator) + .unwrap(); + } + + s +} + +fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_path: &DefPath, + originating_crate: ast::CrateNum, + parameters: &[ty::Ty<'tcx>]) + -> String { + let tcx = ccx.tcx(); + + let mut hash_state = ccx.symbol_hasher().borrow_mut(); + + hash_state.reset(); + + if originating_crate == cstore::LOCAL_CRATE { + hash_state.input_str(&tcx.sess.crate_salt.borrow()[..]); + } else { + hash_state.input_str(&tcx.sess.cstore.crate_salt(originating_crate)); + } + + for component in def_path { + let disambiguator_bytes = [(component.disambiguator >> 0) as u8, + (component.disambiguator >> 8) as u8, + (component.disambiguator >> 16) as u8, + (component.disambiguator >> 24) as u8]; + hash_state.input(&disambiguator_bytes); + } + + 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>, + mut def_id: DefId, + parameters: &[ty::Ty<'tcx>], + suffix: Option<&str>) + -> String { + 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); + let hash = get_symbol_hash(ccx, &def_path, def_id.krate, parameters); + + let mut path = Vec::with_capacity(16); + + if def_id.is_local() { + path.push(ccx.tcx().crate_name.clone()); + } + + path.extend(def_path.into_iter().map(|e| e.data.as_interned_str())); + + if let Some(suffix) = suffix { + path.push(token::intern_and_get_ident(suffix)); + } + + link::mangle(path.into_iter(), Some(&hash[..])) +} + +pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_id: DefId, + parameters: &[ty::Ty<'tcx>]) + -> String { + exported_name_with_opt_suffix(ccx, def_id, parameters, None) +} + +pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_id: DefId, + parameters: &[ty::Ty<'tcx>], + suffix: &str) + -> String { + exported_name_with_opt_suffix(ccx, def_id, parameters, Some(suffix)) +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index d7e79e46720b3..2761110f02144 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/trans/base.rs b/src/librustc_trans/trans/base.rs index 5088dabfbe78e..df90ddc8765d9 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2513,8 +2513,7 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { &item.attrs, llfn, empty_substs, - item.id, - None); + item.id); } else { trans_fn(ccx, &decl, diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index cace98a230f61..e54a26e158333 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -9,7 +9,7 @@ // except according to those terms. -use back::{abi, link}; +use back::{abi, symbol_names}; use llvm::{ValueRef, CallConv, get_param}; use llvm; use middle::weak_lang_items; @@ -32,7 +32,6 @@ use middle::ty::{self, Ty, TyCtxt}; use middle::subst::Substs; use std::cmp; -use std::iter::once; use libc::c_uint; use syntax::abi::Abi; use syntax::attr; @@ -596,8 +595,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attrs: &[ast::Attribute], llwrapfn: ValueRef, param_substs: &'tcx Substs<'tcx>, - id: ast::NodeId, - hash: Option<&str>) { + id: ast::NodeId) { let _icx = push_ctxt("foreign::build_foreign_fn"); let fnty = ccx.tcx().node_id_to_type(id); @@ -606,7 +604,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, unsafe { // unsafe because we call LLVM operations // Build up the Rust function (`foo0` above). - let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id, hash); + let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id); // Build up the foreign wrapper (`foo` above). return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, mty); @@ -617,8 +615,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, body: &hir::Block, param_substs: &'tcx Substs<'tcx>, attrs: &[ast::Attribute], - id: ast::NodeId, - hash: Option<&str>) + id: ast::NodeId) -> ValueRef { let _icx = push_ctxt("foreign::foreign::build_rust_fn"); @@ -626,12 +623,11 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let t = tcx.node_id_to_type(id); let t = monomorphize::apply_param_substs(tcx, param_substs, &t); - let path = - tcx.map.def_path_from_id(id) - .into_iter() - .map(|e| e.data.as_interned_str()) - .chain(once(special_idents::clownshoe_abi.name.as_str())); - let ps = link::mangle(path, hash); + let suffix = special_idents::clownshoe_abi.name.as_str(); + let ps = symbol_names::exported_name_with_suffix(ccx, + tcx.map.local_def_id(id), + param_substs.types.as_slice(), + &suffix); // Compute the type that the function would have if it were just a // normal Rust function. This will be the type of the wrappee fn. diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index c6119416e47ed..76da74b4fc5e5 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -8,7 +8,7 @@ // 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; @@ -33,7 +33,6 @@ use syntax::abi::Abi; use syntax::ast; use syntax::attr; use syntax::errors; -use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: DefId, @@ -117,40 +116,31 @@ 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(); - hash_id.hash(&mut state); - mono_ty.hash(&mut state); + let symbol = symbol_names::exported_name(ccx, + hash_id.def, + hash_id.params.as_slice()); - hash = format!("h{}", state.finish()); - let path = ccx.tcx().map.def_path_from_id(fn_node_id); - exported_name(path, &hash[..]) - }; - - debug!("monomorphize_fn mangled to {}", s); + debug!("monomorphize_fn mangled to {}", symbol); - // This shouldn't need to option dance. - let mut hash_id = Some(hash_id); - let mut mk_lldecl = |abi: Abi| { + let mk_lldecl = |abi: Abi| { let lldecl = if abi != Abi::Rust { - foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s) + foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &symbol) } else { // FIXME(nagisa): perhaps needs a more fine grained selection? See // setup_lldecl below. - declare::define_internal_rust_fn(ccx, &s, mono_ty) + declare::define_internal_rust_fn(ccx, &symbol, mono_ty) }; - ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); + ccx.monomorphized().borrow_mut().insert(hash_id, lldecl); lldecl }; let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| { 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); @@ -175,9 +165,13 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let needs_body = setup_lldecl(d, &i.attrs); if needs_body { if abi != Abi::Rust { - foreign::trans_rust_fn_with_foreign_abi( - ccx, &decl, &body, &[], d, psubsts, fn_node_id, - Some(&hash[..])); + foreign::trans_rust_fn_with_foreign_abi(ccx, + &decl, + &body, + &i.attrs, + d, + psubsts, + fn_node_id); } else { trans_fn(ccx, &decl, @@ -281,7 +275,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, (lldecl, mono_ty, true) } -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct MonoId<'tcx> { pub def: DefId, pub params: &'tcx subst::VecPerParamSpace> 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/compile-fail/dupe-symbols-8.rs b/src/test/compile-fail/dupe-symbols-8.rs deleted file mode 100644 index 3c0e545e19335..0000000000000 --- a/src/test/compile-fail/dupe-symbols-8.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 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. -// -// error-pattern:already defined - - -#![allow(warnings)] - -fn main() { - { - extern fn fail() {} - } - { - extern fn fail() {} - } -} 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; From eb4de06872cfe189b7734caf71a1f5d127f6dac7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 13:18:28 -0500 Subject: [PATCH 08/18] Make closures use stable symbol names. --- src/librustc_trans/trans/closure.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 11c03fe7a7dc7..d67a0cbb006f1 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::{link, symbol_names}; use llvm::{ValueRef, get_params}; use middle::def_id::DefId; use middle::infer; @@ -150,8 +150,9 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let path = ccx.tcx().def_path(closure_id); - let symbol = mangle_internal_name_by_path_and_seq(path, "closure"); + let symbol = symbol_names::exported_name(ccx, + mono_id.def, + mono_id.params.as_slice()); let function_type = ccx.tcx().mk_closure_from_closure_substs(closure_id, Box::new(substs)); let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type); From 4d1259e23cc55a84033cfc44aacc4285c15ecbfd Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 17:38:49 -0500 Subject: [PATCH 09/18] Make drop glue use new symbol naming scheme. --- src/librustc_trans/back/symbol_names.rs | 14 +++++++++++++- src/librustc_trans/trans/glue.rs | 9 +++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index f95bbfbe0a7b6..0112f69a8752b 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -96,7 +96,7 @@ //! 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; +use trans::{CrateContext, gensym_name}; use util::sha2::{Digest, Sha256}; use rustc::middle::cstore; @@ -222,3 +222,15 @@ pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> String { exported_name_with_opt_suffix(ccx, def_id, parameters, 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 hash = get_symbol_hash(ccx, &Vec::new(), cstore::LOCAL_CRATE, &[t]); + link::mangle(path.iter().cloned(), Some(&hash[..])) +} diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index d5f8cff495600..3ae84d1a041c5 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; @@ -256,7 +256,12 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; }; - let fn_nm = 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); let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ccx.tcx().mk_nil()).unwrap_or_else(||{ ccx.sess().bug(&format!("symbol `{}` already defined", fn_nm)); }); From e3a78d81793678dd015200c31d8c80638ce25260 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 18:08:08 -0500 Subject: [PATCH 10/18] Use new symbol naming scheme for fn-pointer-shims. --- src/librustc_trans/trans/callee.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 05e5ac808d030..7790c9aa2a20d 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; @@ -298,8 +298,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_maybe_ref, + "fn_pointer_shim"); + let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty); // From 6351081da85fa4745a4b9f02b196b1a00872ec79 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 18:15:49 -0500 Subject: [PATCH 11/18] Use new symbol naming scheme for fn-once-shims. --- src/librustc_trans/trans/closure.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index d67a0cbb006f1..67fe82fb955db 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, symbol_names}; +use back::symbol_names; use llvm::{ValueRef, get_params}; use middle::def_id::DefId; use middle::infer; @@ -363,7 +363,9 @@ 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_rust_fn(ccx, &function_name, llonce_fn_ty); From 9a1465c43a3f81ee6bce19e2d9cef0760a671957 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 1 Mar 2016 08:16:48 -0500 Subject: [PATCH 12/18] Use new symbol naming scheme for object shims. --- src/librustc_trans/trans/meth.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 7397ccc2505f1..7b83f2385f9ea 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; @@ -228,7 +228,9 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, }; // - let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); + let function_name = symbol_names::internal_name_from_type_and_suffix(ccx, + shim_fn_ty, + "object_shim"); let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty); let empty_substs = tcx.mk_substs(Substs::trans_empty()); From a3dc0485799c7bc66df3ba730f04e7ae00c9cf2d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 15 Feb 2016 15:41:16 -0500 Subject: [PATCH 13/18] Use new symbol names for items of various kinds. --- src/librustc_trans/trans/base.rs | 18 +++++++++--------- .../{issue-17718.rs => issue-17718-aux.rs} | 0 src/test/run-pass/backtrace.rs | 6 +++--- src/test/run-pass/issue-17718.rs | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) rename src/test/auxiliary/{issue-17718.rs => issue-17718-aux.rs} (100%) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index df90ddc8765d9..473f21e10c6ce 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -29,8 +29,7 @@ pub use self::ValueOrigin::*; use super::CrateTranslation; use super::ModuleTranslation; -use back::link::mangle_exported_name; -use back::{link, abi}; +use back::{link, abi, symbol_names}; use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; @@ -2732,16 +2731,17 @@ 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 + let path = ccx.tcx().map.def_path_from_id(id); path.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) + let def_id = ccx.tcx().map.local_def_id(id); + symbol_names::exported_name(ccx, def_id, &[ty]) } } } @@ -2764,7 +2764,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { debug!("get_item_val: id={} item={:?}", id, item); let val = match item { hir_map::NodeItem(i) => { - let ty = ccx.tcx().node_id_to_type(i.id); + let ty = ccx.tcx().erase_regions(&ccx.tcx().node_id_to_type(i.id)); let sym = || exported_name(ccx, id, ty, &i.attrs); let v = match i.node { @@ -2836,7 +2836,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { match ni.node { hir::ForeignItemFn(..) => { let abi = ccx.tcx().map.get_foreign_abi(id); - let ty = ccx.tcx().node_id_to_type(ni.id); + let ty = ccx.tcx().erase_regions(&ccx.tcx().node_id_to_type(ni.id)); let name = foreign::link_name(&ni); foreign::register_foreign_item_fn(ccx, abi, ty, &name, &ni.attrs) } @@ -2854,7 +2854,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { v.node.data.fields() }; assert!(!fields.is_empty()); - let ty = ccx.tcx().node_id_to_type(id); + let ty = ccx.tcx().erase_regions(&ccx.tcx().node_id_to_type(id)); let parent = ccx.tcx().map.get_parent(id); let enm = ccx.tcx().map.expect_item(parent); let sym = exported_name(ccx, id, ty, &enm.attrs); @@ -2878,7 +2878,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { }; let parent = ccx.tcx().map.get_parent(id); let struct_item = ccx.tcx().map.expect_item(parent); - let ty = ccx.tcx().node_id_to_type(ctor_id); + let ty = ccx.tcx().erase_regions(&ccx.tcx().node_id_to_type(ctor_id)); let sym = exported_name(ccx, id, ty, &struct_item.attrs); let llfn = register_fn(ccx, struct_item.span, sym, ctor_id, ty); attributes::inline(llfn, attributes::InlineAttr::Hint); @@ -2908,7 +2908,7 @@ fn register_method(ccx: &CrateContext, attrs: &[ast::Attribute], span: Span) -> ValueRef { - let mty = ccx.tcx().node_id_to_type(id); + let mty = ccx.tcx().erase_regions(&ccx.tcx().node_id_to_type(id)); let sym = exported_name(ccx, id, mty, &attrs); 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/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 3fb52f8c8b4dc..e97e125b28374 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -51,7 +51,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(" - backtrace::foo"), "bad output: {}", s); // Make sure the stack trace is *not* printed @@ -61,7 +61,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(" - backtrace::foo"), "bad output2: {}", s); // Make sure a stack trace is printed @@ -71,7 +71,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(" - backtrace::double"), "bad output3: {}", s); // Make sure a stack trace isn't printed too many times 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}; From b3272131a700c808c4def801be382c172fcaa638 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 17 Feb 2016 23:42:36 -0500 Subject: [PATCH 14/18] Add a test to verify that we have reproducible compiler builds. --- src/test/run-make/reproducible-build/Makefile | 14 ++ .../reproducible-build-aux.rs | 38 ++++++ .../reproducible-build/reproducible-build.rs | 128 ++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 src/test/run-make/reproducible-build/Makefile create mode 100644 src/test/run-make/reproducible-build/reproducible-build-aux.rs create mode 100644 src/test/run-make/reproducible-build/reproducible-build.rs diff --git a/src/test/run-make/reproducible-build/Makefile b/src/test/run-make/reproducible-build/Makefile new file mode 100644 index 0000000000000..7447024ee43b1 --- /dev/null +++ b/src/test/run-make/reproducible-build/Makefile @@ -0,0 +1,14 @@ +-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" + cmp "$(TMPDIR)/reproducible-build1" "$(TMPDIR)/reproducible-build2" || 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" + cmp "$(TMPDIR)/reproducible-build1-debug" "$(TMPDIR)/reproducible-build2-debug" || 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" + cmp "$(TMPDIR)/reproducible-build1-opt" "$(TMPDIR)/reproducible-build2-opt" || 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(); +} + + From 25cbff102d99754e4a5ee9f0d25a4263f1beb42a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 18 Feb 2016 13:05:13 -0500 Subject: [PATCH 15/18] Salt test crates in buildsystem. --- mk/tests.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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)) From 9d5ce13004987d8d332b2fe2a298dedb8f4b668e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 26 Feb 2016 16:25:25 -0500 Subject: [PATCH 16/18] Make the compiler emit an error if the crate graph contains two crates with the same crate-name and crate-salt but different SVHs. --- src/librustc_driver/driver.rs | 10 ++-- src/librustc_metadata/creader.rs | 48 +++++++++++++++++-- src/librustc_metadata/cstore.rs | 3 ++ src/librustc_metadata/decoder.rs | 4 +- src/librustc_metadata/diagnostics.rs | 2 + src/librustc_metadata/macro_import.rs | 11 +++-- src/librustc_plugin/load.rs | 11 +++-- src/librustc_trans/back/symbol_names.rs | 19 ++++---- src/test/auxiliary/inline-default-methods.rs | 2 + src/test/auxiliary/issue-13698.rs | 2 + src/test/auxiliary/issue-15318.rs | 2 + src/test/auxiliary/issue-17476.rs | 1 + src/test/auxiliary/issue-19190-3.rs | 2 + src/test/auxiliary/issue-20646.rs | 2 + src/test/auxiliary/issue-20727.rs | 2 + src/test/auxiliary/issue-21092.rs | 2 + src/test/auxiliary/issue-21801.rs | 2 + src/test/auxiliary/issue-22025.rs | 2 + src/test/auxiliary/issue-27362.rs | 2 + src/test/auxiliary/issue-29584.rs | 2 + .../extern-overrides-distribution/Makefile | 2 +- src/test/run-make/issue-26006/Makefile | 2 +- 22 files changed, 107 insertions(+), 28 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b8b2d39fe5d76..07f04bb2ba593 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -526,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); @@ -755,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 = try!(time(time_passes, "language item collection", || { sess.track_errors(|| { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d05728d11cd32..11cb2b8a818f4 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -55,6 +55,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 +147,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 +276,38 @@ impl<'a> CrateReader<'a> { } } + fn verify_no_symbol_conflicts(&self, + crate_name: &str, + span: Span, + metadata: &MetadataBlob) { + let disambiguator = decoder::get_crate_disambiguator(metadata.as_slice()); + + // Check for (potential) conflicts with the local crate + if self.local_crate_name == crate_name && + &self.sess.crate_disambiguator.borrow()[..] == 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, E0520, + "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 +318,7 @@ impl<'a> CrateReader<'a> { -> (ast::CrateNum, Rc, cstore::CrateSource) { self.verify_rustc_version(name, span, &lib.metadata); + self.verify_no_symbol_conflicts(name, span, &lib.metadata); // Claim this crate number and cache it let cnum = self.next_crate_num; @@ -713,12 +750,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, } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index a96da6bf4d66a..1e265c546c5c4 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -250,6 +250,9 @@ 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 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(); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 1fe221348fc2e..5cff53e4a90bc 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1320,8 +1320,8 @@ pub fn maybe_get_crate_name(data: &[u8]) -> Option { pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str { let crate_doc = rbml::Doc::new(data); - let salt_doc = reader::get_doc(crate_doc, tag_crate_disambiguator); - let slice: &'a str = salt_doc.as_str_slice(); + let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator); + let slice: &'a str = disambiguator_doc.as_str_slice(); slice } diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 50b9ea5755086..ebc7a4b461e68 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) + E0520, // two dependencies have same (crate-name, disambiguator) but different SVH } 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_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/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 0112f69a8752b..2d2101391e24d 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -78,11 +78,12 @@ //! //! - 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 "salt" value via the -//! `-C metadata` commandline argument. This salt is then fed into the symbol -//! hash of every exported item. Consequently, the symbols in two identical -//! crates but with different salts are not in conflict with each other. This -//! facility is mainly intended to be used by build tools like Cargo. +//! 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 //! ------------------------------- @@ -118,12 +119,12 @@ pub fn def_id_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_id: DefId) -> String { let def_path = if def_id.is_local() { s.push_str(&tcx.crate_name[..]); s.push_str("/"); - s.push_str(&tcx.sess.crate_salt.borrow()[..]); + s.push_str(&tcx.sess.crate_disambiguator.borrow()[..]); &def_path[..] } else { s.push_str(&tcx.sess.cstore.crate_name(def_id.krate)[..]); s.push_str("/"); - s.push_str(&tcx.sess.cstore.crate_salt(def_id.krate)); + s.push_str(&tcx.sess.cstore.crate_disambiguator(def_id.krate)); &def_path[1..] }; @@ -150,9 +151,9 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, hash_state.reset(); if originating_crate == cstore::LOCAL_CRATE { - hash_state.input_str(&tcx.sess.crate_salt.borrow()[..]); + hash_state.input_str(&tcx.sess.crate_disambiguator.borrow()[..]); } else { - hash_state.input_str(&tcx.sess.cstore.crate_salt(originating_crate)); + hash_state.input_str(&tcx.sess.cstore.crate_disambiguator(originating_crate)); } for component in def_path { 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-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/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 From 00c206fd8787e3c388d7129e26060f08dc8d8d8a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 1 Mar 2016 08:18:21 -0500 Subject: [PATCH 17/18] Remove old symbol naming code. --- src/librustc_trans/back/link.rs | 237 +----------------------- src/librustc_trans/back/symbol_names.rs | 92 ++++++++- 2 files changed, 89 insertions(+), 240 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index c6c1180c76637..f343fe5088a83 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -22,13 +22,9 @@ use session::search_paths::PathKind; use session::Session; use middle::cstore::{self, CrateStore, LinkMeta}; use middle::cstore::{LinkagePreference, NativeLibraryKind}; -use middle::def_id::DefId; 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; @@ -38,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; @@ -82,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 { @@ -195,182 +136,6 @@ pub fn build_link_meta(sess: &Session, 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() -} - -pub fn def_to_string(_tcx: &TyCtxt, did: DefId) -> String { - format!("{}:{}", did.krate, did.index.as_usize()) -} - -// 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()); - symbol_hasher.input_str(&tcx.sess.crate_disambiguator.borrow()[..]); - symbol_hasher.input_str("-"); - symbol_hasher.input(&tcx.sess.cstore.encode_type(tcx, t, def_to_string)); - // 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/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 2d2101391e24d..f7078c1101545 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -107,9 +107,8 @@ use rustc::front::map::definitions::DefPath; use std::fmt::Write; use syntax::ast; -use syntax::parse::token; +use syntax::parse::token::{self, InternedString}; use serialize::hex::ToHex; -use super::link; pub fn def_id_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_id: DefId) -> String { @@ -206,7 +205,7 @@ fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path.push(token::intern_and_get_ident(suffix)); } - link::mangle(path.into_iter(), Some(&hash[..])) + mangle(path.into_iter(), Some(&hash[..])) } pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -233,5 +232,90 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx> let path = [token::intern(&t.to_string()).as_str(), gensym_name(suffix).as_str()]; let hash = get_symbol_hash(ccx, &Vec::new(), cstore::LOCAL_CRATE, &[t]); - link::mangle(path.iter().cloned(), Some(&hash[..])) + 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 } From f6b0f17e440ae8f5ef60f7a9bd59b24378b166a5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 1 Mar 2016 08:19:00 -0500 Subject: [PATCH 18/18] Add a "link-guard" to avoid accidentally linking to a wrong dylib at runtime. We want to prevent compiling something against one version of a dynamic library and then, at runtime accidentally using a different version of the dynamic library. With the old symbol-naming scheme this could not happen because every symbol had the SVH in it and you'd get an error by the dynamic linker when using the wrong version of a dylib. With the new naming scheme this isn't the case any more, so this patch adds the "link-guard" to prevent this error case. This is implemented as follows: - In every crate that we compile, we emit a function called "__rustc_link_guard__" - The body of this function contains calls to the "__rustc_link_guard" functions of all dependencies. - An executable contains a call to it's own "__rustc_link_guard" function. As a consequence the "__rustc_link_guard" function call graph mirrors the crate graph and the dynamic linker will fail if a wrong dylib is loaded somewhere because its "__rustc_link_guard" function will contain a different SVH in its name. --- src/librustc/middle/cstore.rs | 7 ++ src/librustc_metadata/creader.rs | 4 +- src/librustc_metadata/csearch.rs | 5 + src/librustc_metadata/cstore.rs | 2 +- src/librustc_metadata/decoder.rs | 6 +- src/librustc_trans/back/linker.rs | 21 ++++ src/librustc_trans/trans/base.rs | 24 ++++ src/librustc_trans/trans/link_guard.rs | 116 ++++++++++++++++++++ src/librustc_trans/trans/mod.rs | 1 + src/test/run-make/link-guard/Makefile | 13 +++ src/test/run-make/link-guard/bad/lib.rs | 16 +++ src/test/run-make/link-guard/good/lib.rs | 16 +++ src/test/run-make/link-guard/main.rs | 15 +++ src/test/run-make/relocation-model/Makefile | 4 +- 14 files changed, 241 insertions(+), 9 deletions(-) create mode 100644 src/librustc_trans/trans/link_guard.rs create mode 100644 src/test/run-make/link-guard/Makefile create mode 100644 src/test/run-make/link-guard/bad/lib.rs create mode 100644 src/test/run-make/link-guard/good/lib.rs create mode 100644 src/test/run-make/link-guard/main.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 144e3afdeb38c..fe020ec7899ec 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -204,7 +204,11 @@ pub trait CrateStore<'tcx> : Any { fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; fn is_allocator(&self, cnum: ast::CrateNum) -> bool; fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; + /// 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) @@ -385,6 +389,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec { 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) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 11cb2b8a818f4..493994fd74a5d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -277,10 +277,10 @@ impl<'a> CrateReader<'a> { } fn verify_no_symbol_conflicts(&self, - crate_name: &str, 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 && @@ -318,7 +318,7 @@ impl<'a> CrateReader<'a> { -> (ast::CrateNum, Rc, cstore::CrateSource) { self.verify_rustc_version(name, span, &lib.metadata); - self.verify_no_symbol_conflicts(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; diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index e47a14ba7f716..5c328ad216bca 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -340,6 +340,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { 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 crate_hash(&self, cnum: ast::CrateNum) -> Svh { let cdata = self.get_crate_data(cnum); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 1e265c546c5c4..17c485c73497f 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -248,7 +248,7 @@ 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()) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5cff53e4a90bc..2322fe7499551 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1311,10 +1311,10 @@ 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() }) } @@ -1331,7 +1331,7 @@ pub fn get_crate_triple(data: &[u8]) -> Option { 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") } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 55192bdf74484..e80f8f0fe8342 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -23,6 +23,7 @@ use session::config::CrateTypeDylib; use session::config; use syntax::ast; use trans::CrateTranslation; +use trans::link_guard; /// Linker abstraction used by back::link to build up the command to invoke a /// linker. @@ -359,6 +360,26 @@ impl<'a> Linker for MsvcLinker<'a> { for symbol in symbols { try!(writeln!(f, " {}", symbol)); } + + // Add link-guard symbols + { + // local crate + let symbol = link_guard::link_guard_name(&trans.link.crate_name[..], + &trans.link.crate_hash); + try!(writeln!(f, " {}", symbol)); + } + // statically linked dependencies + for (i, format) in formats[&CrateTypeDylib].iter().enumerate() { + if *format == Linkage::Static { + let cnum = (i + 1) as ast::CrateNum; + let crate_name = cstore.original_crate_name(cnum); + let svh = cstore.crate_hash(cnum); + + let symbol = link_guard::link_guard_name(&crate_name[..], &svh); + try!(writeln!(f, " {}", symbol)); + } + } + Ok(()) })(); if let Err(e) = res { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 473f21e10c6ce..2fe8fe64e019d 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -77,6 +77,7 @@ use trans::expr; use trans::foreign; use trans::glue; use trans::intrinsic; +use trans::link_guard; use trans::machine; use trans::machine::{llsize_of, llsize_of_real}; use trans::meth; @@ -2668,6 +2669,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { unsafe { llvm::LLVMPositionBuilderAtEnd(bld, llbb); + link_guard::insert_reference_to_link_guard(ccx, llbb); debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(ccx); let (start_fn, args) = if use_start_lang_item { @@ -3213,6 +3215,8 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, collector::print_collection_results(&ccx); } + emit_link_guard_if_necessary(&shared_ccx); + for ccx in shared_ccx.iter() { if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); @@ -3273,6 +3277,8 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, if sess.entry_fn.borrow().is_some() { reachable_symbols.push("main".to_string()); } + reachable_symbols.push(link_guard::link_guard_name(&link_meta.crate_name, + &link_meta.crate_hash)); // For the purposes of LTO, we add to the reachable set all of the upstream // reachable extern fns. These functions are all part of the public ABI of @@ -3316,6 +3322,24 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, } } +fn emit_link_guard_if_necessary(shared_ccx: &SharedCrateContext) { + let link_meta = shared_ccx.link_meta(); + let link_guard_name = link_guard::link_guard_name(&link_meta.crate_name, + &link_meta.crate_hash); + let link_guard_name = CString::new(link_guard_name).unwrap(); + + // Check if the link-guard has already been emitted in a codegen unit + let link_guard_already_emitted = shared_ccx.iter().any(|ccx| { + let link_guard = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), + link_guard_name.as_ptr()) }; + !link_guard.is_null() + }); + + if !link_guard_already_emitted { + link_guard::get_or_insert_link_guard(&shared_ccx.get_ccx(0)); + } +} + /// We visit all the items in the krate and translate them. We do /// this in two walks. The first walk just finds module items. It then /// walks the full contents of those module items and translates all diff --git a/src/librustc_trans/trans/link_guard.rs b/src/librustc_trans/trans/link_guard.rs new file mode 100644 index 0000000000000..94606cafce5de --- /dev/null +++ b/src/librustc_trans/trans/link_guard.rs @@ -0,0 +1,116 @@ +// Copyright 2012-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. + +use back::svh::Svh; +use libc::c_uint; +use llvm; +use std::ffi::CString; +use std::ptr; +use trans::attributes; +use trans::builder; +use trans::CrateContext; +use trans::declare; +use trans::type_::Type; + +const GUARD_PREFIX: &'static str = "__rustc_link_guard_"; + +pub fn link_guard_name(crate_name: &str, crate_svh: &Svh) -> String { + + let mut guard_name = String::new(); + + guard_name.push_str(GUARD_PREFIX); + guard_name.push_str(crate_name); + guard_name.push_str("_"); + guard_name.push_str(crate_svh.as_str()); + + guard_name +} + +pub fn get_or_insert_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) + -> llvm::ValueRef { + + let guard_name = link_guard_name(&ccx.tcx().crate_name[..], + &ccx.link_meta().crate_hash); + + let guard_function = unsafe { + let guard_name_c_string = CString::new(&guard_name[..]).unwrap(); + llvm::LLVMGetNamedValue(ccx.llmod(), guard_name_c_string.as_ptr()) + }; + + if guard_function != ptr::null_mut() { + return guard_function; + } + + let llfty = Type::func(&[], &Type::void(ccx)); + let guard_function = declare::define_cfn(ccx, + &guard_name[..], + llfty, + ccx.tcx().mk_nil()).unwrap_or_else(|| { + ccx.sess().bug("Link guard already defined."); + }); + + attributes::emit_uwtable(guard_function, true); + attributes::unwind(guard_function, false); + + let bld = ccx.raw_builder(); + unsafe { + let llbb = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), + guard_function, + "link_guard_top\0".as_ptr() as *const _); + llvm::LLVMPositionBuilderAtEnd(bld, llbb); + + for crate_num in ccx.sess().cstore.crates() { + if !ccx.sess().cstore.is_explicitly_linked(crate_num) { + continue; + } + + let crate_name = ccx.sess().cstore.original_crate_name(crate_num); + let svh = ccx.sess().cstore.crate_hash(crate_num); + + let dependency_guard_name = link_guard_name(&crate_name[..], &svh); + + let decl = declare::declare_cfn(ccx, + &dependency_guard_name[..], + llfty, + ccx.tcx().mk_nil()); + attributes::unwind(decl, false); + + llvm::LLVMPositionBuilderAtEnd(bld, llbb); + + let args: &[llvm::ValueRef] = &[]; + llvm::LLVMRustBuildCall(bld, + decl, + args.as_ptr(), + args.len() as c_uint, + 0 as *mut _, + builder::noname()); + } + + llvm::LLVMBuildRetVoid(bld); + } + + guard_function +} + +pub fn insert_reference_to_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + llbb: llvm::BasicBlockRef) { + let guard_function = get_or_insert_link_guard(ccx); + + unsafe { + llvm::LLVMPositionBuilderAtEnd(ccx.raw_builder(), llbb); + let args: &[llvm::ValueRef] = &[]; + llvm::LLVMRustBuildCall(ccx.raw_builder(), + guard_function, + args.as_ptr(), + args.len() as c_uint, + 0 as *mut _, + builder::noname()); + } +} diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index 1b8bab7a4ee70..08ef4a7750389 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -53,6 +53,7 @@ mod foreign; mod glue; mod inline; mod intrinsic; +pub mod link_guard; mod llrepr; mod machine; mod _match; 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