From 6fdeecf62f413171ad9762bb42b2d794eb4f4967 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 10 Feb 2016 10:04:45 -0500 Subject: [PATCH 01/45] 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 f85d87413843e..08b87e83a6c4b 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 9ac7216165caf..62318f13a8aa8 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -478,9 +478,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 e677ea962f9cf..a082b0f21f11b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -143,7 +143,7 @@ pub fn def_to_u64(did: DefId) -> u64 { (did.krate as u64) << 32 | (did.index.as_usize() as u64) } -pub fn def_to_string(did: DefId) -> String { +pub fn def_to_string(_tcx: &TyCtxt, did: DefId) -> String { format!("{}:{}", did.krate, did.index.as_usize()) } @@ -2078,11 +2078,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 4718732c8a037..67e77ba3315c9 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -37,7 +37,7 @@ use encoder; pub struct ctxt<'a, 'tcx: 'a> { pub diag: &'a Handler, // Def -> str Callback: - pub ds: fn(DefId) -> String, + pub ds: fn(&TyCtxt<'tcx>, DefId) -> String, // The type context. pub tcx: &'a TyCtxt<'tcx>, pub abbrevs: &'a abbrev_map<'tcx> @@ -99,7 +99,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx }; } ty::TyEnum(def, substs) => { - write!(w, "t[{}|", (cx.ds)(def.did)); + write!(w, "t[{}|", (cx.ds)(cx.tcx, def.did)); enc_substs(w, cx, substs); write!(w, "]"); } @@ -137,7 +137,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx } ty::TyFnDef(def_id, substs, f) => { write!(w, "F"); - write!(w, "{}|", (cx.ds)(def_id)); + write!(w, "{}|", (cx.ds)(cx.tcx, def_id)); enc_substs(w, cx, substs); enc_bare_fn_ty(w, cx, f); } @@ -152,12 +152,12 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx write!(w, "p[{}|{}|{}]", idx, space.to_uint(), name); } ty::TyStruct(def, substs) => { - write!(w, "a[{}|", (cx.ds)(def.did)); + write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did)); enc_substs(w, cx, substs); write!(w, "]"); } ty::TyClosure(def, ref substs) => { - write!(w, "k[{}|", (cx.ds)(def)); + write!(w, "k[{}|", (cx.ds)(cx.tcx, def)); enc_substs(w, cx, &substs.func_substs); for ty in &substs.upvar_tys { enc_ty(w, cx, ty); @@ -310,7 +310,7 @@ fn enc_bound_region(w: &mut Cursor>, cx: &ctxt, br: ty::BoundRegion) { } ty::BrNamed(d, name) => { write!(w, "[{}|{}]", - (cx.ds)(d), + (cx.ds)(cx.tcx, d), name); } ty::BrFresh(id) => { @@ -324,7 +324,7 @@ fn enc_bound_region(w: &mut Cursor>, cx: &ctxt, br: ty::BoundRegion) { pub fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, s: ty::TraitRef<'tcx>) { - write!(w, "{}|", (cx.ds)(s.def_id)); + write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id)); enc_substs(w, cx, s.substs); } @@ -408,8 +408,8 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut Cursor>, pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, v: &ty::TypeParameterDef<'tcx>) { write!(w, "{}:{}|{}|{}|{}|", - v.name, (cx.ds)(v.def_id), - v.space.to_uint(), v.index, (cx.ds)(v.default_def_id)); + v.name, (cx.ds)(cx.tcx, v.def_id), + v.space.to_uint(), v.index, (cx.ds)(cx.tcx, v.default_def_id)); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); enc_object_lifetime_default(w, cx, v.object_lifetime_default); } @@ -417,7 +417,7 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx> pub fn enc_region_param_def(w: &mut Cursor>, cx: &ctxt, v: &ty::RegionParameterDef) { write!(w, "{}:{}|{}|{}|", - v.name, (cx.ds)(v.def_id), + v.name, (cx.ds)(cx.tcx, v.def_id), v.space.to_uint(), v.index); for &r in &v.bounds { write!(w, "R"); @@ -477,7 +477,7 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, enc_ty(w, cx, data); } ty::Predicate::ObjectSafe(trait_def_id) => { - write!(w, "O{}|", (cx.ds)(trait_def_id)); + write!(w, "O{}|", (cx.ds)(cx.tcx, trait_def_id)); } } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index acb458f8cc6ee..20fc74caad9f1 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 5027a79279353ca86d7ebb1f3fb9cc03361b84b4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sat, 13 Feb 2016 12:55:04 -0500 Subject: [PATCH 02/45] 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 530b99cba920c..a9c94a4522ba9 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -97,6 +97,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { if ty_v.did == fn_id { my_id = ast_v.node.data.id(); } ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id())); + ccx.external_srcs().borrow_mut().insert(ast_v.node.data.id(), ty_v.did); } } hir::ItemStruct(ref struct_def, _) => { @@ -105,6 +106,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { non-tuple struct") } else { ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id())); + ccx.external_srcs().borrow_mut().insert(struct_def.id(), fn_id); my_id = struct_def.id(); } } From 606c985a50c588a320efb1441471589211744f56 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 12 Feb 2016 12:43:13 -0500 Subject: [PATCH 03/45] Make CrateStore::crate_name() return an InternedString to avoid unnecessary allocations. --- src/librustc/middle/cstore.rs | 5 +++-- src/librustc/middle/ty/mod.rs | 5 +++-- src/librustc_metadata/csearch.rs | 4 ++-- src/librustc_trans/save/mod.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 08b87e83a6c4b..b89fd92e3c59a 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/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 050024d0e94ea..d36112daa032d 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -2680,14 +2680,15 @@ impl<'tcx> TyCtxt<'tcx> { { dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor); } + /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` /// with the name of the crate containing the impl. - pub fn span_of_impl(&self, impl_did: DefId) -> Result { + pub fn span_of_impl(&self, impl_did: DefId) -> Result { if impl_did.is_local() { let node_id = self.map.as_local_node_id(impl_did).unwrap(); Ok(self.map.span(node_id)) } else { - Err(self.sess.cstore.crate_name(impl_did.krate)) + Err(self.crate_name(impl_did.krate)) } } } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 62318f13a8aa8..9514317056ab3 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -334,9 +334,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 78e91e00baa71..4bbb762469373 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -90,7 +90,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { for n in self.tcx.sess.cstore.crates() { result.push(CrateData { - name: self.tcx.sess.cstore.crate_name(n), + name: (&self.tcx.sess.cstore.crate_name(n)[..]).to_owned(), number: n, }); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 15aeca9204a64..aab5c960df353 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -241,7 +241,7 @@ impl Clean for CrateNum { } }); ExternalCrate { - name: cx.sess().cstore.crate_name(self.0), + name: (&cx.sess().cstore.crate_name(self.0)[..]).to_owned(), attrs: cx.sess().cstore.crate_attrs(self.0).clean(cx), primitives: primitives, } From c7e54d72792d49961930d13e854c8748eee1cd82 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Feb 2016 08:44:06 -0500 Subject: [PATCH 04/45] 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 33ec974c52739..bfcc1759b955d 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -69,10 +69,10 @@ impl fmt::Display for Mode { #[derive(Clone)] pub struct Config { // The library paths required for running the compiler - pub compile_lib_path: String, + pub compile_lib_path: PathBuf, // The library paths required for running compiled programs - pub run_lib_path: String, + pub run_lib_path: PathBuf, // The rustc executable pub rustc_path: PathBuf, diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 96b52eaa0ad0f..51bc9d71f883c 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -118,9 +118,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 5293eee9459cf..efad2038f82f7 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -316,7 +316,7 @@ fn run_pretty_test_revision(config: &Config, testpaths, pretty_type.to_owned()), props.exec_env.clone(), - &config.compile_lib_path, + config.compile_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), Some(src)) } @@ -635,7 +635,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPa testpaths, proc_args, environment, - &config.run_lib_path, + config.run_lib_path.to_str().unwrap(), None, None); } @@ -1315,7 +1315,7 @@ fn exec_compiled_test(config: &Config, props: &TestProps, testpaths, make_run_args(config, props, testpaths), env, - &config.run_lib_path, + config.run_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), None) } @@ -1387,7 +1387,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, &aux_testpaths, aux_args, Vec::new(), - &config.compile_lib_path, + config.compile_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), None); if !auxres.status.success() { @@ -1410,7 +1410,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps, testpaths, args, props.rustc_env.clone(), - &config.compile_lib_path, + config.compile_lib_path.to_str().unwrap(), Some(aux_dir.to_str().unwrap()), input) } From 32a2e9a8e15ee93dbd663fa3849604979df1142f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 12 Feb 2016 08:41:30 -0500 Subject: [PATCH 05/45] 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 34726a7a6c8ec..ef89b5d25b887 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -166,7 +166,7 @@ impl<'doc> Doc<'doc> { } } - pub fn get<'a>(&'a self, tag: usize) -> Doc<'a> { + pub fn get(&self, tag: usize) -> Doc<'doc> { reader::get_doc(*self, tag) } @@ -174,7 +174,7 @@ impl<'doc> Doc<'doc> { self.start == self.end } - pub fn as_str_slice<'a>(&'a self) -> &'a str { + pub fn as_str_slice(&self) -> &'doc str { str::from_utf8(&self.data[self.start..self.end]).unwrap() } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b89fd92e3c59a..718a9fd58dea4 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 3507a119e5455..ec607314f45c0 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -66,7 +66,7 @@ impl Svh { &self.hash } - pub fn calculate(metadata: &Vec, krate: &hir::Crate) -> Svh { + pub fn calculate(crate_disambiguator: &str, krate: &hir::Crate) -> Svh { // FIXME (#14132): This is better than it used to be, but it still not // ideal. We now attempt to hash only the relevant portions of the // Crate AST as well as the top-level crate attributes. (However, @@ -78,9 +78,9 @@ impl Svh { // avoid collisions. let mut state = SipHasher::new(); - for data in metadata { - data.hash(&mut state); - } + "crate_disambiguator".hash(&mut state); + crate_disambiguator.len().hash(&mut state); + crate_disambiguator.hash(&mut state); { let mut visit = svh_visitor::make(&mut state, krate); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 55b873c06630a..b75ccb3f7ee8f 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 dc30b4f91a985..9ba6abb962ead 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -568,8 +568,6 @@ impl RustcDefaultCalls { continue; } let crate_types = driver::collect_crate_types(sess, attrs); - let metadata = driver::collect_crate_metadata(sess, attrs); - *sess.crate_metadata.borrow_mut() = metadata; for &style in &crate_types { let fname = link::filename_for_input(sess, style, &id, &t_outputs); println!("{}", diff --git a/src/librustc_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 9514317056ab3..f9446d7667c69 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -345,6 +345,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 0c736feeefeee..f24c489b7c2af 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1295,6 +1295,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 a082b0f21f11b..a58c24eb09fa8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1877,6 +1877,10 @@ fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) { rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name); } +fn encode_crate_disambiguator(rbml_w: &mut Encoder, crate_disambiguator: &str) { + rbml_w.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator); +} + fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) { rbml_w.wr_tagged_str(tag_crate_triple, triple); } @@ -1987,6 +1991,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, encode_crate_name(rbml_w, &ecx.link_meta.crate_name); encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple); encode_hash(rbml_w, &ecx.link_meta.crate_hash); + encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.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 20fc74caad9f1..01ef33637d58b 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 3a756fea50382b6beb3b4d2fcc593e59f0eadd8c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 12:30:38 -0500 Subject: [PATCH 06/45] 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 b75ccb3f7ee8f..1af01a412239e 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 c77f44eeee81021660c3c2cd86540b7449973417 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 13:01:44 -0500 Subject: [PATCH 07/45] Make monomorphized functions use stable symbol names. --- src/librustc/middle/ty/mod.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 223 ++++++++++++++++++ src/librustc_trans/lib.rs | 1 + src/librustc_trans/trans/context.rs | 3 +- src/librustc_trans/trans/mod.rs | 1 + src/librustc_trans/trans/monomorphize.rs | 27 +-- ...-intrinsic.rs => typeid-intrinsic-aux1.rs} | 0 ...intrinsic2.rs => typeid-intrinsic-aux2.rs} | 0 src/test/run-pass/typeid-intrinsic.rs | 8 +- 9 files changed, 241 insertions(+), 24 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%) diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index d36112daa032d..d4af14cf40907 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -2688,7 +2688,7 @@ impl<'tcx> TyCtxt<'tcx> { let node_id = self.map.as_local_node_id(impl_did).unwrap(); Ok(self.map.span(node_id)) } else { - Err(self.crate_name(impl_did.krate)) + Err(self.sess.cstore.crate_name(impl_did.krate)) } } } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs new file mode 100644 index 0000000000000..de188ec9960ee --- /dev/null +++ b/src/librustc_trans/back/symbol_names.rs @@ -0,0 +1,223 @@ +// 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, Instance}; +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_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_disambiguator(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_disambiguator.borrow()[..]); + } else { + hash_state.input_str(&tcx.sess.cstore.crate_disambiguator(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>, + instance: &Instance<'tcx>, + suffix: Option<&str>) + -> String { + let &Instance { def: mut def_id, params: parameters } = instance; + + 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.as_slice()); + + 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>, + instance: &Instance<'tcx>) + -> String { + exported_name_with_opt_suffix(ccx, instance, None) +} + +pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: &Instance<'tcx>, + suffix: &str) + -> String { + exported_name_with_opt_suffix(ccx, instance, Some(suffix)) +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f8bbde6010940..b9f92bcc4d961 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -69,6 +69,7 @@ pub mod back { pub mod linker; pub mod link; pub mod lto; + pub mod symbol_names; pub mod write; pub mod msvc; } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 046e05dd0710a..a3d387afa96f7 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -25,7 +25,8 @@ use trans::debuginfo; use trans::declare; use trans::glue::DropGlueKind; use trans::mir::CachedMir; -use trans::monomorphize::Instance; +use trans::Instance; + use trans::collector::{TransItem, TransItemState}; use trans::type_::{Type, TypeNames}; use middle::subst::{Substs, VecPerParamSpace}; diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index c5ab0d4e74421..f77f7c30987c8 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -15,6 +15,7 @@ pub use self::base::trans_crate; pub use self::context::CrateContext; pub use self::common::gensym_name; pub use self::disr::Disr; +pub use self::monomorphize::Instance; #[macro_use] mod macros; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 63fb8c5fb5e1c..6dd8d651012e0 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use back::link::exported_name; +use back::symbol_names; use llvm::ValueRef; use llvm; use middle::def_id::DefId; use middle::infer::normalize_associated_type; use middle::subst; use middle::subst::{Subst, Substs}; +use middle::ty::{self, Ty, TyCtxt}; use middle::ty::fold::{TypeFolder, TypeFoldable}; use trans::attributes; use trans::base::{push_ctxt}; @@ -22,7 +23,6 @@ use trans::base::trans_fn; use trans::base; use trans::common::*; use trans::declare; -use middle::ty::{self, Ty, TyCtxt}; use trans::Disr; use rustc::front::map as hir_map; use rustc::util::ppaux; @@ -33,7 +33,6 @@ use syntax::attr; use syntax::errors; use std::fmt; -use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: DefId, @@ -90,22 +89,13 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, monomorphizing.insert(fn_id, depth + 1); } - let hash; - let s = { - let mut state = SipHasher::new(); - instance.hash(&mut state); - mono_ty.hash(&mut state); - - hash = format!("h{}", state.finish()); - let path = ccx.tcx().map.def_path(fn_id); - exported_name(path, &hash[..]) - }; + let symbol = symbol_names::exported_name(ccx, &instance); - debug!("monomorphize_fn mangled to {}", s); - assert!(declare::get_defined_value(ccx, &s).is_none()); + debug!("monomorphize_fn mangled to {}", symbol); + assert!(declare::get_defined_value(ccx, &symbol).is_none()); // FIXME(nagisa): perhaps needs a more fine grained selection? - let lldecl = declare::define_internal_fn(ccx, &s, mono_ty); + let lldecl = declare::define_internal_fn(ccx, &symbol, mono_ty); // FIXME(eddyb) Doubt all extern fn should allow unwinding. attributes::unwind(lldecl, true); @@ -137,9 +127,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); attributes::from_fn_attrs(ccx, attrs, lldecl); - let is_first = !ccx.available_monomorphizations().borrow().contains(&s); + let is_first = !ccx.available_monomorphizations().borrow() + .contains(&symbol); if is_first { - ccx.available_monomorphizations().borrow_mut().insert(s.clone()); + ccx.available_monomorphizations().borrow_mut().insert(symbol.clone()); } let trans_everywhere = attr::requests_inline(attrs); diff --git a/src/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/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 6f60c9e1fd1a6d7349cede373ac1ffe6d0757b87 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 13:18:28 -0500 Subject: [PATCH 08/45] Make closures use stable symbol names. --- src/librustc_trans/trans/closure.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index dbabc3f54c594..810bcd466c6cc 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_param, get_params}; use middle::def_id::DefId; use middle::infer; @@ -152,8 +152,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let path = tcx.def_path(closure_id); - let symbol = mangle_internal_name_by_path_and_seq(path, "closure"); + let symbol = symbol_names::exported_name(ccx, &instance); // Compute the rust-call form of the closure call method. let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any); From 7a5a98857965830dc0c2f58d853f3abc813f7dd7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 17:38:49 -0500 Subject: [PATCH 09/45] 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 de188ec9960ee..f9bed0019dfd2 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, Instance}; +use trans::{CrateContext, Instance, gensym_name}; use util::sha2::{Digest, Sha256}; use rustc::middle::cstore; @@ -221,3 +221,15 @@ pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> String { exported_name_with_opt_suffix(ccx, instance, Some(suffix)) } + +/// Only symbols that are invisible outside their compilation unit should use a +/// name generated by this function. +pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + t: ty::Ty<'tcx>, + suffix: &str) + -> String { + let path = [token::intern(&t.to_string()).as_str(), + gensym_name(suffix).as_str()]; + let 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 de4b1ba858a6c..aa205898114d6 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -14,7 +14,7 @@ use std; -use back::link; +use back::symbol_names; use llvm; use llvm::{ValueRef, get_param}; use middle::lang_items::ExchangeFreeFnLangItem; @@ -259,7 +259,12 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; }; - let fn_nm = link::mangle_internal_name_by_type_and_seq(ccx, t, "drop"); + let suffix = match g { + DropGlueKind::Ty(_) => "drop", + DropGlueKind::TyContents(_) => "drop_contents", + }; + + let fn_nm = symbol_names::internal_name_from_type_and_suffix(ccx, t, suffix); assert!(declare::get_defined_value(ccx, &fn_nm).is_none()); let llfn = declare::declare_cfn(ccx, &fn_nm, llfnty); ccx.available_drop_glues().borrow_mut().insert(g, fn_nm); From 23e54b24adad2c04c1080a7c3d54611452c5232f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 18:08:08 -0500 Subject: [PATCH 10/45] 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 1013c5d64b609..e15fe3698fe42 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -18,7 +18,7 @@ pub use self::CalleeData::*; pub use self::CallArgs::*; use arena::TypedArena; -use back::link; +use back::symbol_names; use llvm::{self, ValueRef, get_params}; use middle::cstore::LOCAL_CRATE; use middle::def_id::DefId; @@ -378,8 +378,10 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("tuple_fn_ty: {:?}", tuple_fn_ty); // - let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, - "fn_pointer_shim"); + let function_name = + symbol_names::internal_name_from_type_and_suffix(ccx, + bare_fn_ty, + "fn_pointer_shim"); let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty); // From 8ef638e6fa0eccc0c7ce3d28555cc14c0ddf10f7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 14 Feb 2016 18:15:49 -0500 Subject: [PATCH 11/45] Use new symbol naming scheme for fn-once-shims. --- src/librustc_trans/trans/closure.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 810bcd466c6cc..ff3235385a9b0 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -9,7 +9,7 @@ // except according to those terms. use arena::TypedArena; -use back::{link, symbol_names}; +use back::symbol_names; use llvm::{ValueRef, get_param, get_params}; use middle::def_id::DefId; use middle::infer; @@ -382,7 +382,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( }); // Create the by-value helper. - let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); + let function_name = + symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim"); let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty); let (block_arena, fcx): (TypedArena<_>, FunctionContext); From 68de171890cccc376cf55db165d9c6595ee75743 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 1 Mar 2016 08:16:48 -0500 Subject: [PATCH 12/45] Use new symbol naming scheme for object shims. --- src/librustc_trans/trans/meth.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index ae619ceb30b01..f45de10bca853 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -11,7 +11,7 @@ use std::rc::Rc; use arena::TypedArena; -use back::link; +use back::symbol_names; use llvm::{ValueRef, get_params}; use middle::def_id::DefId; use middle::infer; @@ -89,7 +89,8 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, let sig = infer::normalize_associated_type(tcx, &sig); let fn_ty = FnType::new(ccx, method_ty.fn_abi(), &sig, &[]); - let function_name = link::mangle_internal_name_by_type_and_seq(ccx, method_ty, "object_shim"); + let function_name = + symbol_names::internal_name_from_type_and_suffix(ccx, method_ty, "object_shim"); let llfn = declare::define_internal_fn(ccx, &function_name, method_ty); let empty_substs = tcx.mk_substs(Substs::empty()); From 7def3768c6ffa85f774e96b85b42a4f9a7ce78c5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 15 Feb 2016 15:41:16 -0500 Subject: [PATCH 13/45] Use new symbol names for items of various kinds. --- src/librustc_trans/back/link.rs | 97 +------------------ src/librustc_trans/trans/base.rs | 13 +-- src/librustc_trans/trans/callee.rs | 2 +- src/librustc_trans/trans/consts.rs | 2 +- .../{issue-17718.rs => issue-17718-aux.rs} | 0 src/test/run-pass/backtrace.rs | 6 +- src/test/run-pass/issue-17718.rs | 4 +- 7 files changed, 17 insertions(+), 107 deletions(-) rename src/test/auxiliary/{issue-17718.rs => issue-17718-aux.rs} (100%) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 01ef33637d58b..2a9bd6618a373 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -24,11 +24,9 @@ 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 middle::ty::TyCtxt; +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 +36,14 @@ 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::parse::token::InternedString; use syntax::attr::AttrMetaMethods; use rustc_front::hir; @@ -195,50 +191,10 @@ 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, ., _, $ @@ -324,53 +280,6 @@ pub fn mangle>(path: PI, hash: Option<&str>) - 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/trans/base.rs b/src/librustc_trans/trans/base.rs index 1d8daf9d86b4a..e903fc2811d02 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + //! Translate the completed AST to the LLVM IR. //! //! Some functions here, such as trans_block and trans_expr, return a value -- @@ -29,8 +30,7 @@ pub use self::ValueOrigin::*; use super::CrateTranslation; use super::ModuleTranslation; -use back::link::mangle_exported_name; -use back::link; +use back::{link, symbol_names}; use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; @@ -2421,10 +2421,11 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { } pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - id: ast::NodeId, - ty: Ty<'tcx>, + instance: Instance<'tcx>, attrs: &[ast::Attribute]) -> String { + let id = ccx.tcx().map.as_local_node_id(instance.def).unwrap(); + match ccx.external_srcs().borrow().get(&id) { Some(&did) => { let sym = ccx.sess().cstore.item_symbol(did); @@ -2438,16 +2439,16 @@ pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Use provided name Some(name) => name.to_string(), _ => { - let path = ccx.tcx().map.def_path_from_id(id); if attr::contains_name(attrs, "no_mangle") { // Don't mangle + 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) + symbol_names::exported_name(ccx, &instance) } } } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index e15fe3698fe42..6fe4598c1ba3c 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -515,7 +515,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Some(hir_map::NodeImplItem(&hir::ImplItem { ref attrs, id, span, node: hir::ImplItemKind::Method(..), .. })) => { - let sym = exported_name(ccx, id, ty, attrs); + let sym = exported_name(ccx, instance, attrs); if declare::get_defined_value(ccx, &sym).is_some() { ccx.sess().span_fatal(span, diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 7e6b24969100b..4cdb64a9bfb71 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -1032,7 +1032,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) // we need to get the symbol from metadata instead of // using the current crate's name/version // information in the hash of the symbol - let sym = exported_name(ccx, id, ty, attrs); + let sym = exported_name(ccx, instance, attrs); debug!("making {}", sym); // Create the global before evaluating the initializer; diff --git a/src/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 2a98706351a8b..88c5fb2c40891 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -57,7 +57,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 @@ -67,7 +67,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 @@ -77,7 +77,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 9c965b786c26fa8828a482320e2443bede3eea66 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 17 Feb 2016 23:42:36 -0500 Subject: [PATCH 14/45] 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 fafdfa8bdc2cf762d84ca2e18215d3e11caf3af5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 18 Feb 2016 13:05:13 -0500 Subject: [PATCH 15/45] 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 2eebb7b60588902c51d6d8dd9e695c6babaa8aa2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 26 Feb 2016 16:25:25 -0500 Subject: [PATCH 16/45] 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 | 11 +++-- 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, 103 insertions(+), 24 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 1af01a412239e..4c64923456d84 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 = 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 f24c489b7c2af..79209a7d26da2 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1297,8 +1297,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 f9bed0019dfd2..6edf8db9bf7e6 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 //! ------------------------------- 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 82b5f1d8690ec538557ce3f355add91e3809ba51 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 1 Mar 2016 08:18:21 -0500 Subject: [PATCH 17/45] Remove old symbol naming code. --- src/librustc_trans/back/link.rs | 144 ------------------------ src/librustc_trans/back/symbol_names.rs | 92 ++++++++++++++- 2 files changed, 88 insertions(+), 148 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 2a9bd6618a373..a8e83bdb6b7f6 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -22,9 +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::TyCtxt; use trans::CrateTranslation; use util::common::time; use util::fs::fix_windows_verbatim_for_gcc; @@ -43,7 +41,6 @@ use std::str; use flate; use syntax::ast; use syntax::codemap::Span; -use syntax::parse::token::InternedString; use syntax::attr::AttrMetaMethods; use rustc_front::hir; @@ -78,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 { @@ -191,95 +136,6 @@ pub fn build_link_meta(sess: &Session, return r; } -pub fn def_to_string(_tcx: &TyCtxt, did: DefId) -> String { - format!("{}:{}", did.krate, did.index.as_usize()) -} - -// 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 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 6edf8db9bf7e6..7f42cc673c73f 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 { @@ -207,7 +206,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>, @@ -232,5 +231,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 247570732205fd226981082ee5c96c0abf5fed21 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 1 Mar 2016 08:19:00 -0500 Subject: [PATCH 18/45] 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 718a9fd58dea4..34af4826c3ea4 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 f9446d7667c69..fb4dbbba8da49 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -339,6 +339,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 79209a7d26da2..00810ec71abbf 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1288,10 +1288,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() }) } @@ -1308,7 +1308,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 b6b330c3734b0..934e0e16a9688 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 { 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 e903fc2811d02..6bbf323ef5e8b 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -79,6 +79,7 @@ use trans::expr; use trans::glue; use trans::inline; use trans::intrinsic; +use trans::link_guard; use trans::machine; use trans::machine::{llalign_of_min, llsize_of, llsize_of_real}; use trans::meth; @@ -2382,6 +2383,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 { @@ -2758,6 +2760,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); @@ -2818,6 +2822,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 @@ -2861,6 +2867,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 f77f7c30987c8..2e71128a1e78b 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -53,6 +53,7 @@ mod expr; mod glue; mod inline; mod intrinsic; +pub mod link_guard; mod machine; mod _match; mod meth; 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 From 65c0b7c2922a4f7f5bbee4c23fb12ffb6f27d278 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 05:31:51 -0400 Subject: [PATCH 19/45] track def-id for inlined items --- src/librustc/front/map/collector.rs | 11 +++++++-- src/librustc/front/map/definitions.rs | 27 +++++++++++++++++++++- src/librustc/front/map/mod.rs | 8 +++++-- src/librustc_metadata/astencode.rs | 10 +++++---- src/librustc_metadata/decoder.rs | 32 +++++++++++++++++++++------ 5 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/librustc/front/map/collector.rs b/src/librustc/front/map/collector.rs index 11aea3727299d..7f66b56b2d317 100644 --- a/src/librustc/front/map/collector.rs +++ b/src/librustc/front/map/collector.rs @@ -14,7 +14,7 @@ use super::MapEntry::*; use rustc_front::hir::*; use rustc_front::util; use rustc_front::intravisit::{self, Visitor}; -use middle::def_id::{CRATE_DEF_INDEX, DefIndex}; +use middle::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use std::iter::repeat; use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; use syntax::codemap::Span; @@ -50,6 +50,7 @@ impl<'ast> NodeCollector<'ast> { parent: &'ast InlinedParent, parent_node: NodeId, parent_def_path: DefPath, + parent_def_id: DefId, map: Vec>, definitions: Definitions) -> NodeCollector<'ast> { @@ -60,8 +61,14 @@ impl<'ast> NodeCollector<'ast> { definitions: definitions, }; + assert_eq!(parent_def_path.krate, parent_def_id.krate); + let root_path = Box::new(InlinedRootPath { + data: parent_def_path.data, + def_id: parent_def_id, + }); + collector.insert_entry(parent_node, RootInlinedParent(parent)); - collector.create_def(parent_node, DefPathData::InlinedRoot(parent_def_path)); + collector.create_def(parent_node, DefPathData::InlinedRoot(root_path)); collector } diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/front/map/definitions.rs index 0f99d85b083fe..bf5fd736526a1 100644 --- a/src/librustc/front/map/definitions.rs +++ b/src/librustc/front/map/definitions.rs @@ -60,13 +60,38 @@ pub struct DefData { } pub type DefPath = Vec; +/// Root of an inlined item. We track the `DefPath` of the item within +/// the original crate but also its def-id. This is kind of an +/// augmented version of a `DefPath` that includes a `DefId`. This is +/// all sort of ugly but the hope is that inlined items will be going +/// away soon anyway. +/// +/// Some of the constraints that led to the current approach: +/// +/// - I don't want to have a `DefId` in the main `DefPath` because +/// that gets serialized for incr. comp., and when reloaded the +/// `DefId` is no longer valid. I'd rather maintain the invariant +/// that every `DefId` is valid, and a potentially outdated `DefId` is +/// represented as a `DefPath`. +/// - (We don't serialize def-paths from inlined items, so it's ok to have one here.) +/// - We need to be able to extract the def-id from inline items to +/// make the symbol name. In theory we could retrace it from the +/// data, but the metadata doesn't have the required indices, and I +/// don't want to write the code to create one just for this. +/// - It may be that we don't actually need `data` at all. We'll have +/// to see about that. +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct InlinedRootPath { + pub data: Vec, + pub def_id: DefId, +} #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum DefPathData { // Root: these should only be used for the root nodes, because // they are treated specially by the `def_path` function. CrateRoot, - InlinedRoot(DefPath), + InlinedRoot(Box), // Catch-all for random DefId things like DUMMY_NODE_ID Misc, diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs index dfc8560b58de0..a1355046f48c1 100644 --- a/src/librustc/front/map/mod.rs +++ b/src/librustc/front/map/mod.rs @@ -12,7 +12,8 @@ pub use self::Node::*; pub use self::PathElem::*; use self::MapEntry::*; use self::collector::NodeCollector; -pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; +pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, + DisambiguatedDefPathData, InlinedRootPath}; use dep_graph::{DepGraph, DepNode}; @@ -322,7 +323,8 @@ impl<'ast> Map<'ast> { id = p, RootCrate | - RootInlinedParent(_) => // FIXME(#2369) clarify story about cross-crate dep tracking + RootInlinedParent(_) => + // FIXME(#32015) clarify story about cross-crate dep tracking return DepNode::Krate, NotPresent => @@ -958,6 +960,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, parent_path: Vec, parent_def_path: DefPath, + parent_def_id: DefId, ii: InlinedItem, fold_ops: F) -> &'ast InlinedItem { @@ -987,6 +990,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, ii_parent, ii_parent_id, parent_def_path, + parent_def_id, mem::replace(&mut *map.map.borrow_mut(), vec![]), mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new())); ii_parent.ii.visit(&mut collector); diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 5c5574c3a8300..60f7110764699 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -125,6 +125,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, tcx: &TyCtxt<'tcx>, parent_path: Vec, parent_def_path: ast_map::DefPath, + parent_did: DefId, ast_doc: rbml::Doc, orig_did: DefId) -> &'tcx InlinedItem { @@ -149,6 +150,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, let ii = ast_map::map_decoded_item(&dcx.tcx.map, parent_path, parent_def_path, + parent_did, decode_ast(ast_doc), dcx); let name = match *ii { @@ -349,8 +351,8 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem { } } -fn decode_ast(par_doc: rbml::Doc) -> InlinedItem { - let chi_doc = par_doc.get(c::tag_tree as usize); +fn decode_ast(item_doc: rbml::Doc) -> InlinedItem { + let chi_doc = item_doc.get(c::tag_tree as usize); let mut rbml_r = reader::Decoder::new(chi_doc); rbml_r.read_opaque(|decoder, _| Decodable::decode(decoder)).unwrap() } @@ -1280,8 +1282,8 @@ fn encode_item_ast(rbml_w: &mut Encoder, item: &hir::Item) { } #[cfg(test)] -fn decode_item_ast(par_doc: rbml::Doc) -> hir::Item { - let chi_doc = par_doc.get(c::tag_tree as usize); +fn decode_item_ast(item_doc: rbml::Doc) -> hir::Item { + let chi_doc = item_doc.get(c::tag_tree as usize); let mut d = reader::Decoder::new(chi_doc); Decodable::decode(&mut d).unwrap() } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 00810ec71abbf..5c3c7ad1b3023 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -803,25 +803,43 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &TyCtxt<'tcx>, id: DefIndex) debug!("Looking up item: {:?}", id); let item_doc = cdata.lookup_item(id); let item_did = item_def_id(item_doc, cdata); + let parent_def_id = DefId { + krate: cdata.cnum, + index: def_key(cdata, id).parent.unwrap() + }; let mut parent_path = item_path(item_doc); parent_path.pop(); let mut parent_def_path = def_path(cdata, id); parent_def_path.pop(); if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) { - let ii = decode_inlined_item(cdata, tcx, parent_path, + let ii = decode_inlined_item(cdata, + tcx, + parent_path, parent_def_path, - ast_doc, item_did); + parent_def_id, + ast_doc, + item_did); return FoundAst::Found(ii); } else if let Some(parent_did) = item_parent_item(cdata, item_doc) { // Remove the last element from the paths, since we are now // trying to inline the parent. - parent_path.pop(); - parent_def_path.pop(); + let grandparent_def_id = DefId { + krate: cdata.cnum, + index: def_key(cdata, parent_def_id.index).parent.unwrap() + }; + let mut grandparent_path = parent_path; + grandparent_path.pop(); + let mut grandparent_def_path = parent_def_path; + grandparent_def_path.pop(); let parent_doc = cdata.lookup_item(parent_did.index); if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, tag_ast as usize) { - let ii = decode_inlined_item(cdata, tcx, parent_path, - parent_def_path, - ast_doc, parent_did); + let ii = decode_inlined_item(cdata, + tcx, + grandparent_path, + grandparent_def_path, + grandparent_def_id, + ast_doc, + parent_did); if let &InlinedItem::Item(ref i) = ii { return FoundAst::FoundParent(parent_did, i); } From 7b6270b53794adf62e16918a159e5e5eecb9a60e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 05:40:14 -0400 Subject: [PATCH 20/45] store krate information more uniformly make DefPath store krate and enable uniform access to crate_name/crate_disambiguator --- src/librustc/front/map/definitions.rs | 77 ++++++++++++++++--------- src/librustc/middle/ty/context.rs | 18 +++++- src/librustc/session/mod.rs | 5 +- src/librustc_driver/driver.rs | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/decoder.rs | 6 +- src/librustc_metadata/encoder.rs | 2 +- src/librustc_trans/back/link.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 23 +++----- src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/collector.rs | 22 +++---- 11 files changed, 91 insertions(+), 70 deletions(-) diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/front/map/definitions.rs index bf5fd736526a1..4d5da12cad239 100644 --- a/src/librustc/front/map/definitions.rs +++ b/src/librustc/front/map/definitions.rs @@ -59,7 +59,54 @@ pub struct DefData { pub node_id: ast::NodeId, } -pub type DefPath = Vec; +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct DefPath { + /// the path leading from the crate root to the item + pub data: Vec, + + /// what krate root is this path relative to? + pub krate: ast::CrateNum, +} + +impl DefPath { + pub fn is_local(&self) -> bool { + self.krate == LOCAL_CRATE + } + + pub fn make(start_krate: ast::CrateNum, + start_index: DefIndex, + mut get_key: FN) -> DefPath + where FN: FnMut(DefIndex) -> DefKey + { + let mut krate = start_krate; + let mut data = vec![]; + let mut index = Some(start_index); + loop { + let p = index.unwrap(); + let key = get_key(p); + match key.disambiguated_data.data { + DefPathData::CrateRoot => { + assert!(key.parent.is_none()); + break; + } + DefPathData::InlinedRoot(ref p) => { + assert!(key.parent.is_none()); + assert!(!p.def_id.is_local()); + data.extend(p.data.iter().cloned().rev()); + krate = p.def_id.krate; + break; + } + _ => { + data.push(key.disambiguated_data); + index = key.parent; + } + } + } + data.reverse(); + DefPath { data: data, krate: krate } + } +} + /// Root of an inlined item. We track the `DefPath` of the item within /// the original crate but also its def-id. This is kind of an /// augmented version of a `DefPath` that includes a `DefId`. This is @@ -141,7 +188,7 @@ impl Definitions { /// will be the path of the item in the external crate (but the /// path will begin with the path to the external crate). pub fn def_path(&self, index: DefIndex) -> DefPath { - make_def_path(index, |p| self.def_key(p)) + DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p)) } pub fn opt_def_index(&self, node: ast::NodeId) -> Option { @@ -247,29 +294,3 @@ impl DefPathData { } } -pub fn make_def_path(start_index: DefIndex, mut get_key: FN) -> DefPath - where FN: FnMut(DefIndex) -> DefKey -{ - let mut result = vec![]; - let mut index = Some(start_index); - while let Some(p) = index { - let key = get_key(p); - match key.disambiguated_data.data { - DefPathData::CrateRoot => { - assert!(key.parent.is_none()); - break; - } - DefPathData::InlinedRoot(ref p) => { - assert!(key.parent.is_none()); - result.extend(p.iter().cloned().rev()); - break; - } - _ => { - result.push(key.disambiguated_data); - index = key.parent; - } - } - } - result.reverse(); - result -} diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 4e81297a789a8..6acd094c1f90d 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -15,7 +15,7 @@ use front::map as ast_map; use session::Session; use lint; use middle; -use middle::cstore::CrateStore; +use middle::cstore::{CrateStore, LOCAL_CRATE}; use middle::def::DefMap; use middle::def_id::DefId; use middle::free_region::FreeRegionMap; @@ -422,6 +422,22 @@ pub struct TyCtxt<'tcx> { } impl<'tcx> TyCtxt<'tcx> { + pub fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString { + if cnum == LOCAL_CRATE { + self.crate_name.clone() + } else { + self.sess.cstore.crate_name(cnum) + } + } + + pub fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString { + if cnum == LOCAL_CRATE { + self.sess.crate_disambiguator.get().as_str() + } else { + self.sess.cstore.crate_name(cnum) + } + } + pub fn type_parameter_def(&self, node_id: NodeId) -> ty::TypeParameterDef<'tcx> diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 36dc8eabc89f2..3e6878408681c 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -24,6 +24,7 @@ use syntax::diagnostics; use syntax::feature_gate; use syntax::parse; use syntax::parse::ParseSess; +use syntax::parse::token; use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; @@ -69,7 +70,7 @@ pub struct Session { // 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 crate_disambiguator: Cell, pub features: RefCell, /// The maximum recursion limit for potentially infinitely recursive @@ -486,7 +487,7 @@ pub fn build_session_(sopts: config::Options, plugin_attributes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FnvHashMap()), - crate_disambiguator: RefCell::new(String::new()), + crate_disambiguator: Cell::new(token::intern("")), features: RefCell::new(feature_gate::Features::new()), recursion_limit: Cell::new(64), next_node_id: Cell::new(1), diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4c64923456d84..96e819ea91fee 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -501,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_disambiguator.borrow_mut() = compute_crate_disambiguator(sess); + sess.crate_disambiguator.set(token::intern(&compute_crate_disambiguator(sess))); time(time_passes, "recursion limit", || { middle::recursion_limit::update_recursion_limit(sess, &krate); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 493994fd74a5d..c1144387553f0 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -284,7 +284,7 @@ impl<'a> CrateReader<'a> { // Check for (potential) conflicts with the local crate if self.local_crate_name == crate_name && - &self.sess.crate_disambiguator.borrow()[..] == disambiguator { + self.sess.crate_disambiguator.get().as_str() == disambiguator { span_fatal!(self.sess, span, E0519, "the current crate is indistinguishable from one of its \ dependencies: it has the same crate-name `{}` and was \ diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 5c3c7ad1b3023..562525e956a89 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1779,9 +1779,5 @@ fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey { pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath { debug!("def_path(id={:?})", id); - hir_map::definitions::make_def_path(id, |parent| { - debug!("def_path: parent={:?}", parent); - let parent_doc = cdata.lookup_item(parent); - def_key(parent_doc) - }) + hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent)) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a58c24eb09fa8..73ac64adbb2a5 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1991,7 +1991,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, encode_crate_name(rbml_w, &ecx.link_meta.crate_name); encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple); encode_hash(rbml_w, &ecx.link_meta.crate_hash); - encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.borrow()); + encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str()); encode_dylib_dependency_formats(rbml_w, &ecx); let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index a8e83bdb6b7f6..64d117100543f 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -130,7 +130,7 @@ pub fn build_link_meta(sess: &Session, -> LinkMeta { let r = LinkMeta { crate_name: name.to_owned(), - crate_hash: Svh::calculate(&sess.crate_disambiguator.borrow()[..], krate), + crate_hash: Svh::calculate(&sess.crate_disambiguator.get().as_str(), krate), }; info!("{:?}", r); return r; diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 7f42cc673c73f..a67b6841f02a1 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -111,23 +111,18 @@ use syntax::parse::token::{self, InternedString}; use serialize::hex::ToHex; pub fn def_id_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_id: DefId) -> String { - let def_path = tcx.def_path(def_id); - let mut s = String::with_capacity(def_path.len() * 16); + def_path_to_string(tcx, &def_path) +} - let def_path = if def_id.is_local() { - s.push_str(&tcx.crate_name[..]); - s.push_str("/"); - 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_disambiguator(def_id.krate)); - &def_path[1..] - }; +pub fn def_path_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_path: &DefPath) -> String { + let mut s = String::with_capacity(def_path.data.len() * 16); - for component in def_path { + s.push_str(&tcx.crate_name(def_path.krate)); + s.push_str("/"); + s.push_str(&tcx.crate_disambiguator(def_path.krate)); + + for component in &def_path.data { write!(s, "::{}[{}]", component.data.as_interned_str(), diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 6bbf323ef5e8b..160596683f1c2 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2444,7 +2444,7 @@ pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, 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() + path.data.last().unwrap().data.to_string() } else { match weak_lang_items::link_name(attrs) { Some(name) => name.to_string(), diff --git a/src/librustc_trans/trans/collector.rs b/src/librustc_trans/trans/collector.rs index ab8f7d6bec3d5..3f3da36be0695 100644 --- a/src/librustc_trans/trans/collector.rs +++ b/src/librustc_trans/trans/collector.rs @@ -1261,28 +1261,20 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn push_item_name(ccx: &CrateContext, def_id: DefId, output: &mut String) { - if def_id.is_local() { - let node_id = ccx.tcx().map.as_local_node_id(def_id).unwrap(); - let inlined_from = ccx.external_srcs() - .borrow() - .get(&node_id) - .map(|def_id| *def_id); - - if let Some(extern_def_id) = inlined_from { - push_item_name(ccx, extern_def_id, output); - return; - } + let def_path = ccx.tcx().def_path(def_id); - output.push_str(&ccx.link_meta().crate_name); - output.push_str("::"); - } + // some_crate:: + output.push_str(&ccx.tcx().crate_name(def_path.krate)); + output.push_str("::"); - for part in ccx.tcx().def_path(def_id) { + // foo::bar::ItemName:: + for part in ccx.tcx().def_path(def_id).data { output.push_str(&format!("{}[{}]::", part.data.as_interned_str(), part.disambiguator)); } + // remove final "::" output.pop(); output.pop(); } From 5e26508744850e9c541e83d27f710cf221360fbc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 05:47:18 -0400 Subject: [PATCH 21/45] refactor DefPathData variants In particular, remove the name from the Impl, since that name is synthesized and is not predictable (it tends to break incr. comp.). Also rename the variants to be a bit more uniform and remove some distinctions that we were not really taking advantage of anywhere. --- src/librustc/front/map/collector.rs | 25 +++++++++++++++---------- src/librustc/front/map/definitions.rs | 22 +++++++++------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/librustc/front/map/collector.rs b/src/librustc/front/map/collector.rs index 7f66b56b2d317..4ae03b1b9d722 100644 --- a/src/librustc/front/map/collector.rs +++ b/src/librustc/front/map/collector.rs @@ -133,11 +133,16 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { // Pick the def data. This need not be unique, but the more // information we encapsulate into let def_data = match i.node { - ItemDefaultImpl(..) | ItemImpl(..) => DefPathData::Impl(i.name), - ItemEnum(..) | ItemStruct(..) | ItemTrait(..) => DefPathData::Type(i.name), - ItemExternCrate(..) | ItemMod(..) => DefPathData::Mod(i.name), - ItemStatic(..) | ItemConst(..) | ItemFn(..) => DefPathData::Value(i.name), - _ => DefPathData::Misc, + ItemDefaultImpl(..) | ItemImpl(..) => + DefPathData::Impl, + ItemEnum(..) | ItemStruct(..) | ItemTrait(..) | + ItemExternCrate(..) | ItemMod(..) | ItemForeignMod(..) | + ItemTy(..) => + DefPathData::TypeNs(i.name), + ItemStatic(..) | ItemConst(..) | ItemFn(..) => + DefPathData::ValueNs(i.name), + ItemUse(..) => + DefPathData::Misc, }; self.insert_def(i.id, NodeItem(i), def_data); @@ -202,7 +207,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { self.insert_def(foreign_item.id, NodeForeignItem(foreign_item), - DefPathData::Value(foreign_item.name)); + DefPathData::ValueNs(foreign_item.name)); let parent_node = self.parent_node; self.parent_node = foreign_item.id; @@ -222,8 +227,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_trait_item(&mut self, ti: &'ast TraitItem) { let def_data = match ti.node { - MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::Value(ti.name), - TypeTraitItem(..) => DefPathData::Type(ti.name), + MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::ValueNs(ti.name), + TypeTraitItem(..) => DefPathData::TypeNs(ti.name), }; self.insert(ti.id, NodeTraitItem(ti)); @@ -246,8 +251,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_impl_item(&mut self, ii: &'ast ImplItem) { let def_data = match ii.node { - ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::Value(ii.name), - ImplItemKind::Type(..) => DefPathData::Type(ii.name), + ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.name), + ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name), }; self.insert_def(ii.id, NodeImplItem(ii), def_data); diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/front/map/definitions.rs index 4d5da12cad239..82574b852297a 100644 --- a/src/librustc/front/map/definitions.rs +++ b/src/librustc/front/map/definitions.rs @@ -144,10 +144,9 @@ pub enum DefPathData { Misc, // Different kinds of items and item-like things: - Impl(ast::Name), - Type(ast::Name), - Mod(ast::Name), - Value(ast::Name), + Impl, + TypeNs(ast::Name), // something in the type NS + ValueNs(ast::Name), // something in the value NS MacroDef(ast::Name), ClosureExpr, @@ -159,10 +158,6 @@ pub enum DefPathData { StructCtor, // implicit ctor for a tuple-like struct Initializer, // initializer for a const Binding(ast::Name), // pattern binding - - // An external crate that does not have an `extern crate` in this - // crate. - DetachedCrate(ast::Name), } impl Definitions { @@ -247,20 +242,21 @@ impl DefPathData { pub fn as_interned_str(&self) -> InternedString { use self::DefPathData::*; match *self { - Impl(name) | - Type(name) | - Mod(name) | - Value(name) | + TypeNs(name) | + ValueNs(name) | MacroDef(name) | TypeParam(name) | LifetimeDef(name) | EnumVariant(name) | - DetachedCrate(name) | Binding(name) | Field(name) => { name.as_str() } + Impl => { + InternedString::new("{{impl}}") + } + // note that this does not show up in user printouts CrateRoot => { InternedString::new("{{root}}") From 6056c5fbedb3681f9fe5efa5f9befe7ff2f91e73 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 05:35:03 -0400 Subject: [PATCH 22/45] fallout: update codegen-units tests --- .../codegen-units/cross-crate-closures.rs | 8 +++---- .../cross-crate-generic-functions.rs | 8 +++---- .../codegen-units/cross-crate-trait-method.rs | 20 ++++++++-------- src/test/codegen-units/generic-drop-glue.rs | 10 ++++---- src/test/codegen-units/generic-impl.rs | 24 +++++++++---------- .../impl-in-non-instantiated-generic.rs | 2 +- .../instantiation-through-vtable.rs | 8 +++---- .../codegen-units/non-generic-drop-glue.rs | 4 ++-- .../codegen-units/non-generic-functions.rs | 12 +++++----- .../codegen-units/overloaded-operators.rs | 12 +++++----- .../codegen-units/trait-implementations.rs | 20 ++++++++-------- .../codegen-units/trait-method-as-argument.rs | 2 +- .../codegen-units/transitive-drop-glue.rs | 6 ++--- src/test/codegen-units/tuple-drop-glue.rs | 2 +- src/test/codegen-units/unsizing.rs | 8 +++---- .../unused-traits-and-generics.rs | 2 +- 16 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/test/codegen-units/cross-crate-closures.rs b/src/test/codegen-units/cross-crate-closures.rs index 32b07d42fec44..30f3ef12d0743 100644 --- a/src/test/codegen-units/cross-crate-closures.rs +++ b/src/test/codegen-units/cross-crate-closures.rs @@ -19,12 +19,12 @@ extern crate cgu_extern_closures; //~ TRANS_ITEM fn cross_crate_closures::main[0] fn main() { - //~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn[0] - //~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn[0]::{{closure}}[0] + //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0] + //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0]::{{closure}}[0] let _ = cgu_extern_closures::inlined_fn(1, 2); - //~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn_generic[0] - //~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn_generic[0]::{{closure}}[0] + //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn_generic[0] + //~ TRANS_ITEM fn cgu_extern_closures::inlined_fn_generic[0]::{{closure}}[0] let _ = cgu_extern_closures::inlined_fn_generic(3, 4, 5i32); // Nothing should be generated for this call, we just link to the instance instance diff --git a/src/test/codegen-units/cross-crate-generic-functions.rs b/src/test/codegen-units/cross-crate-generic-functions.rs index 82d940a154852..ada1234b852a1 100644 --- a/src/test/codegen-units/cross-crate-generic-functions.rs +++ b/src/test/codegen-units/cross-crate-generic-functions.rs @@ -19,12 +19,12 @@ extern crate cgu_generic_function; //~ TRANS_ITEM fn cross_crate_generic_functions::main[0] fn main() { - //~ TRANS_ITEM fn cgu_generic_function[0]::bar[0] - //~ TRANS_ITEM fn cgu_generic_function[0]::foo[0] + //~ TRANS_ITEM fn cgu_generic_function::bar[0] + //~ TRANS_ITEM fn cgu_generic_function::foo[0] let _ = cgu_generic_function::foo(1u32); - //~ TRANS_ITEM fn cgu_generic_function[0]::bar[0] - //~ TRANS_ITEM fn cgu_generic_function[0]::foo[0] + //~ TRANS_ITEM fn cgu_generic_function::bar[0] + //~ TRANS_ITEM fn cgu_generic_function::foo[0] let _ = cgu_generic_function::foo(2u64); // This should not introduce a codegen item diff --git a/src/test/codegen-units/cross-crate-trait-method.rs b/src/test/codegen-units/cross-crate-trait-method.rs index aa1f6b06c8135..9f29a90bffbf6 100644 --- a/src/test/codegen-units/cross-crate-trait-method.rs +++ b/src/test/codegen-units/cross-crate-trait-method.rs @@ -29,31 +29,31 @@ fn main() // Currently, no object code is generated for trait methods with default // implemenations, unless they are actually called from somewhere. Therefore // we cannot import the implementations and have to create our own inline. - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] let _ = Trait::with_default_impl(0u32); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] let _ = Trait::with_default_impl('c'); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic(0u32, "abc"); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic(0u32, false); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic('x', 1i16); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] let _ = Trait::with_default_impl_generic('y', 0i32); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::u32.Trait[0]::without_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] let _: (u32, char) = Trait::without_default_impl_generic('c'); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::u32.Trait[0]::without_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] let _: (u32, bool) = Trait::without_default_impl_generic(false); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::char.Trait[0]::without_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] let _: (char, char) = Trait::without_default_impl_generic('c'); - //~ TRANS_ITEM fn cgu_export_trait_method[0]::char.Trait[0]::without_default_impl_generic[0] + //~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] let _: (char, bool) = Trait::without_default_impl_generic(false); } diff --git a/src/test/codegen-units/generic-drop-glue.rs b/src/test/codegen-units/generic-drop-glue.rs index f89d6e61bc552..476c84044e686 100644 --- a/src/test/codegen-units/generic-drop-glue.rs +++ b/src/test/codegen-units/generic-drop-glue.rs @@ -49,17 +49,17 @@ struct NonGenericWithDrop(i32); impl Drop for NonGenericWithDrop { fn drop(&mut self) {} -//~ TRANS_ITEM fn generic_drop_glue::NonGenericWithDrop.Drop[0]::drop[0] +//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0] } //~ TRANS_ITEM fn generic_drop_glue::main[0] fn main() { //~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0] - //~ TRANS_ITEM fn generic_drop_glue::StructWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0] let _ = StructWithDrop { x: 0i8, y: 'a' }.x; //~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> - //~ TRANS_ITEM fn generic_drop_glue::StructWithDrop.Drop[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> + //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y; // Should produce no drop glue @@ -71,14 +71,14 @@ fn main() { let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y; //~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0] - //~ TRANS_ITEM fn generic_drop_glue::EnumWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::A::(0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as i32 }; //~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0] - //~ TRANS_ITEM fn generic_drop_glue::EnumWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] let _ = match EnumWithDrop::B::(1.0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as f64 diff --git a/src/test/codegen-units/generic-impl.rs b/src/test/codegen-units/generic-impl.rs index 6e6bb5cbf53c8..a27515fd39b70 100644 --- a/src/test/codegen-units/generic-impl.rs +++ b/src/test/codegen-units/generic-impl.rs @@ -40,11 +40,11 @@ pub struct LifeTimeOnly<'a> { impl<'a> LifeTimeOnly<'a> { - //~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::foo[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::foo[0] pub fn foo(&self) {} - //~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::bar[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::bar[0] pub fn bar(&'a self) {} - //~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::baz[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[1]::baz[0] pub fn baz<'b>(&'b self) {} pub fn non_instantiated(&self) {} @@ -53,27 +53,27 @@ impl<'a> LifeTimeOnly<'a> { //~ TRANS_ITEM fn generic_impl::main[0] fn main() { - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::Struct[0]::get[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new(0i32).get(0i16); - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::Struct[0]::get[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new(0i64).get(0i16); - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0] //~ TRANS_ITEM fn generic_impl::id[0] - //~ TRANS_ITEM fn generic_impl::Struct[0]::get[0] + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0] let _ = Struct::new('c').get(0i16); - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0]<&str> + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<&str> //~ TRANS_ITEM fn generic_impl::id[0]<&str> - //~ TRANS_ITEM fn generic_impl::Struct[0]::get[0], i16> + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0], i16> let _ = Struct::new(Struct::new("str")).get(0i16); - //~ TRANS_ITEM fn generic_impl::Struct[0]::new[0]> + //~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]> //~ TRANS_ITEM fn generic_impl::id[0]> let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str")); } diff --git a/src/test/codegen-units/impl-in-non-instantiated-generic.rs b/src/test/codegen-units/impl-in-non-instantiated-generic.rs index e17a1a7094f2f..a3bfa67e1ae44 100644 --- a/src/test/codegen-units/impl-in-non-instantiated-generic.rs +++ b/src/test/codegen-units/impl-in-non-instantiated-generic.rs @@ -21,7 +21,7 @@ trait SomeTrait { // discovered. pub fn generic_function(x: T) -> (T, i32) { impl SomeTrait for i64 { - //~ TRANS_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::i64.SomeTrait[0]::foo[0] + //~ TRANS_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::{{impl}}[0]::foo[0] fn foo(&self) {} } diff --git a/src/test/codegen-units/instantiation-through-vtable.rs b/src/test/codegen-units/instantiation-through-vtable.rs index 46587b2b0a1b2..b772525122001 100644 --- a/src/test/codegen-units/instantiation-through-vtable.rs +++ b/src/test/codegen-units/instantiation-through-vtable.rs @@ -31,12 +31,12 @@ impl Trait for Struct { fn main() { let s1 = Struct { _a: 0u32 }; - //~ TRANS_ITEM fn instantiation_through_vtable::Struct.Trait[0]::foo[0] - //~ TRANS_ITEM fn instantiation_through_vtable::Struct.Trait[0]::bar[0] + //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] + //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; let s1 = Struct { _a: 0u64 }; - //~ TRANS_ITEM fn instantiation_through_vtable::Struct.Trait[0]::foo[0] - //~ TRANS_ITEM fn instantiation_through_vtable::Struct.Trait[0]::bar[0] + //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] + //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; } diff --git a/src/test/codegen-units/non-generic-drop-glue.rs b/src/test/codegen-units/non-generic-drop-glue.rs index a82e85b7a5315..bd8b0c605aecf 100644 --- a/src/test/codegen-units/non-generic-drop-glue.rs +++ b/src/test/codegen-units/non-generic-drop-glue.rs @@ -19,7 +19,7 @@ struct StructWithDrop { } impl Drop for StructWithDrop { - //~ TRANS_ITEM fn non_generic_drop_glue::StructWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn non_generic_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } @@ -33,7 +33,7 @@ enum EnumWithDrop { } impl Drop for EnumWithDrop { - //~ TRANS_ITEM fn non_generic_drop_glue::EnumWithDrop.Drop[0]::drop[0] + //~ TRANS_ITEM fn non_generic_drop_glue::{{impl}}[1]::drop[0] fn drop(&mut self) {} } diff --git a/src/test/codegen-units/non-generic-functions.rs b/src/test/codegen-units/non-generic-functions.rs index 687ce7fa05cb4..4e2a7c8508468 100644 --- a/src/test/codegen-units/non-generic-functions.rs +++ b/src/test/codegen-units/non-generic-functions.rs @@ -38,31 +38,31 @@ fn bar() { struct Struct { _x: i32 } impl Struct { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0] fn foo() { { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]::foo[0] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[0] fn foo() {} foo(); } { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]::foo[1] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[1] fn foo() {} foo(); } } - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0] fn bar(&self) { { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]::foo[0] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[0] fn foo() {} foo(); } { - //~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]::foo[1] + //~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[1] fn foo() {} foo(); } diff --git a/src/test/codegen-units/overloaded-operators.rs b/src/test/codegen-units/overloaded-operators.rs index 134110222f392..c275eb954b094 100644 --- a/src/test/codegen-units/overloaded-operators.rs +++ b/src/test/codegen-units/overloaded-operators.rs @@ -23,7 +23,7 @@ pub struct Indexable { impl Index for Indexable { type Output = u8; - //~ TRANS_ITEM fn overloaded_operators::Indexable.Index[0]::index[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[0]::index[0] fn index(&self, index: usize) -> &Self::Output { if index >= 3 { &self.data[0] @@ -34,7 +34,7 @@ impl Index for Indexable { } impl IndexMut for Indexable { - //~ TRANS_ITEM fn overloaded_operators::Indexable.IndexMut[0]::index_mut[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[1]::index_mut[0] fn index_mut(&mut self, index: usize) -> &mut Self::Output { if index >= 3 { &mut self.data[0] @@ -45,8 +45,8 @@ impl IndexMut for Indexable { } -//~ TRANS_ITEM fn overloaded_operators::Equatable.::std::cmp::PartialEq[0]::eq[0] -//~ TRANS_ITEM fn overloaded_operators::Equatable.::std::cmp::PartialEq[0]::ne[0] +//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::eq[0] +//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::ne[0] #[derive(PartialEq)] pub struct Equatable(u32); @@ -54,7 +54,7 @@ pub struct Equatable(u32); impl Add for Equatable { type Output = u32; - //~ TRANS_ITEM fn overloaded_operators::Equatable.Add[0]::add[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::add[0] fn add(self, rhs: u32) -> u32 { self.0 + rhs } @@ -63,7 +63,7 @@ impl Add for Equatable { impl Deref for Equatable { type Target = u32; - //~ TRANS_ITEM fn overloaded_operators::Equatable.Deref[0]::deref[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::deref[0] fn deref(&self) -> &Self::Target { &self.0 } diff --git a/src/test/codegen-units/trait-implementations.rs b/src/test/codegen-units/trait-implementations.rs index 590859f15a3e1..2eb2212f0cacd 100644 --- a/src/test/codegen-units/trait-implementations.rs +++ b/src/test/codegen-units/trait-implementations.rs @@ -20,7 +20,7 @@ pub trait SomeTrait { impl SomeTrait for i64 { - //~ TRANS_ITEM fn trait_implementations::i64.SomeTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[0]::foo[0] fn foo(&self) {} fn bar(&self, _: T) {} @@ -28,7 +28,7 @@ impl SomeTrait for i64 { impl SomeTrait for i32 { - //~ TRANS_ITEM fn trait_implementations::i32.SomeTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::foo[0] fn foo(&self) {} fn bar(&self, _: T) {} @@ -42,7 +42,7 @@ pub trait SomeGenericTrait { // Concrete impl of generic trait impl SomeGenericTrait for f64 { - //~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::foo[0] fn foo(&self, _: u32) {} fn bar(&self, _: u32, _: T2) {} @@ -57,25 +57,25 @@ impl SomeGenericTrait for f32 { //~ TRANS_ITEM fn trait_implementations::main[0] fn main() { - //~ TRANS_ITEM fn trait_implementations::i32.SomeTrait[0]::bar[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::bar[0] 0i32.bar('x'); - //~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait[0]::bar[0]<&str> + //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<&str> 0f64.bar(0u32, "&str"); - //~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait[0]::bar[0]<()> + //~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<()> 0f64.bar(0u32, ()); - //~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::foo[0] 0f32.foo('x'); - //~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait[0]::foo[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::foo[0] 0f32.foo(-1i64); - //~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait[0]::bar[0] + //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0] 0f32.bar(0u32, ()); - //~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait[0]::bar[0]<&str, &str> + //~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str> 0f32.bar("&str", "&str"); } diff --git a/src/test/codegen-units/trait-method-as-argument.rs b/src/test/codegen-units/trait-method-as-argument.rs index fdf63df547111..e7006d73ef166 100644 --- a/src/test/codegen-units/trait-method-as-argument.rs +++ b/src/test/codegen-units/trait-method-as-argument.rs @@ -39,7 +39,7 @@ fn take_foo_mut T>(mut f: F, arg: T) -> T { //~ TRANS_ITEM fn trait_method_as_argument::main[0] fn main() { //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] u32> - //~ TRANS_ITEM fn trait_method_as_argument::u32.Trait[0]::foo[0] + //~ TRANS_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0] take_foo_once(Trait::foo, 0u32); //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] char> diff --git a/src/test/codegen-units/transitive-drop-glue.rs b/src/test/codegen-units/transitive-drop-glue.rs index 6982cb9299a55..21bb29199a685 100644 --- a/src/test/codegen-units/transitive-drop-glue.rs +++ b/src/test/codegen-units/transitive-drop-glue.rs @@ -21,7 +21,7 @@ struct Intermediate(Leaf); struct Leaf; impl Drop for Leaf { - //~ TRANS_ITEM fn transitive_drop_glue::Leaf.Drop[0]::drop[0] + //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } @@ -44,12 +44,12 @@ fn main() { //~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0] //~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0] //~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0] - //~ TRANS_ITEM fn transitive_drop_glue::LeafGen.Drop[0]::drop[0] + //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0u32))); //~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0] //~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0] //~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0] - //~ TRANS_ITEM fn transitive_drop_glue::LeafGen.Drop[0]::drop[0] + //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] let _ = RootGen(IntermediateGen(LeafGen(0i16))); } diff --git a/src/test/codegen-units/tuple-drop-glue.rs b/src/test/codegen-units/tuple-drop-glue.rs index 87fcb00eab8c2..1bc235de88e1f 100644 --- a/src/test/codegen-units/tuple-drop-glue.rs +++ b/src/test/codegen-units/tuple-drop-glue.rs @@ -17,7 +17,7 @@ struct Dropped; impl Drop for Dropped { - //~ TRANS_ITEM fn tuple_drop_glue::Dropped.Drop[0]::drop[0] + //~ TRANS_ITEM fn tuple_drop_glue::{{impl}}[0]::drop[0] fn drop(&mut self) {} } diff --git a/src/test/codegen-units/unsizing.rs b/src/test/codegen-units/unsizing.rs index dd90d32858f11..45ba441bc8ba6 100644 --- a/src/test/codegen-units/unsizing.rs +++ b/src/test/codegen-units/unsizing.rs @@ -57,11 +57,11 @@ fn main() { // simple case let bool_sized = &true; - //~ TRANS_ITEM fn unsizing::bool.Trait[0]::foo[0] + //~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0] let _bool_unsized = bool_sized as &Trait; let char_sized = &true; - //~ TRANS_ITEM fn unsizing::char.Trait[0]::foo[0] + //~ TRANS_ITEM fn unsizing::{{impl}}[1]::foo[0] let _char_unsized = char_sized as &Trait; // struct field @@ -70,11 +70,11 @@ fn main() _b: 2, _c: 3.0f64 }; - //~ TRANS_ITEM fn unsizing::f64.Trait[0]::foo[0] + //~ TRANS_ITEM fn unsizing::{{impl}}[2]::foo[0] let _struct_unsized = struct_sized as &Struct; // custom coercion let wrapper_sized = Wrapper(&0u32); - //~ TRANS_ITEM fn unsizing::u32.Trait[0]::foo[0] + //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; } diff --git a/src/test/codegen-units/unused-traits-and-generics.rs b/src/test/codegen-units/unused-traits-and-generics.rs index a4c5099ab9751..8689beb3fb77e 100644 --- a/src/test/codegen-units/unused-traits-and-generics.rs +++ b/src/test/codegen-units/unused-traits-and-generics.rs @@ -85,5 +85,5 @@ impl NonGeneric { } // Only the non-generic methods should be instantiated: -//~ TRANS_ITEM fn unused_traits_and_generics::NonGeneric[0]::foo[0] +//~ TRANS_ITEM fn unused_traits_and_generics::{{impl}}[3]::foo[0] //~ TRANS_ITEM drop-glue i8 From ab9b8441468aed505f83a2ddf74454f9cdfeab33 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 05:50:38 -0400 Subject: [PATCH 23/45] track the extern-crate def-id rather than path We used to track, for each crate, a path that led to the extern-crate that imported it. Instead of that, track the def-id of the extern crate, along with a bit more information, and derive the path on the fly. --- src/librustc/middle/cstore.rs | 33 ++++++++++-- src/librustc/middle/ty/mod.rs | 27 +++++++++- src/librustc_metadata/creader.rs | 86 ++++++++++++++++++++++---------- src/librustc_metadata/csearch.rs | 33 ++++++------ src/librustc_metadata/cstore.rs | 57 +++------------------ src/librustc_metadata/decoder.rs | 4 +- 6 files changed, 141 insertions(+), 99 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 34af4826c3ea4..7cad9b10f85ec 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -127,6 +127,27 @@ pub enum FoundAst<'ast> { NotFound, } +#[derive(Copy, Clone, Debug)] +pub struct ExternCrate { + /// def_id of an `extern crate` in the current crate that caused + /// this crate to be loaded; note that there could be multiple + /// such ids + pub def_id: DefId, + + /// span of the extern crate that caused this to be loaded + pub span: Span, + + /// If true, then this crate is the crate named by the extern + /// crate referenced above. If false, then this crate is a dep + /// of the crate. + pub direct: bool, + + /// Number of links to reach the extern crate `def_id` + /// declaration; used to select the extern crate with the shortest + /// path + pub path_len: usize, +} + /// A store of Rust crates, through with their metadata /// can be accessed. /// @@ -147,7 +168,7 @@ pub trait CrateStore<'tcx> : Any { fn repr_attrs(&self, def: DefId) -> Vec; fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::TypeScheme<'tcx>; - fn item_path(&self, def: DefId) -> Vec; + fn relative_item_path(&self, def: DefId) -> Vec; fn extern_item_path(&self, def: DefId) -> Vec; fn item_name(&self, def: DefId) -> ast::Name; fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId) @@ -203,6 +224,7 @@ pub trait CrateStore<'tcx> : Any { fn is_staged_api(&self, cnum: ast::CrateNum) -> bool; fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; fn is_allocator(&self, cnum: ast::CrateNum) -> bool; + fn extern_crate(&self, cnum: ast::CrateNum) -> Option; fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; /// The name of the crate as it is referred to in source code of the current /// crate. @@ -218,7 +240,8 @@ pub trait CrateStore<'tcx> : Any { fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec; // resolve - fn def_path(&self, def: DefId) -> hir_map::DefPath; + fn def_key(&self, def: DefId) -> hir_map::DefKey; + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath; fn variant_kind(&self, def_id: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; @@ -323,7 +346,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn repr_attrs(&self, def: DefId) -> Vec { unimplemented!() } fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId) -> ty::TypeScheme<'tcx> { unimplemented!() } - fn item_path(&self, def: DefId) -> Vec { unimplemented!() } + fn relative_item_path(&self, def: DefId) -> Vec { unimplemented!() } fn extern_item_path(&self, def: DefId) -> Vec { unimplemented!() } fn item_name(&self, def: DefId) -> ast::Name { unimplemented!() } fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId) @@ -386,6 +409,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } fn is_allocator(&self, cnum: ast::CrateNum) -> bool { unimplemented!() } + fn extern_crate(&self, cnum: ast::CrateNum) -> Option { unimplemented!() } fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec { unimplemented!() } fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() } @@ -404,7 +428,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec { unimplemented!() } // resolve - fn def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() } + fn def_key(&self, def: DefId) -> hir_map::DefKey { unimplemented!() } + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() } fn variant_kind(&self, def_id: DefId) -> Option { unimplemented!() } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { unimplemented!() } diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index d4af14cf40907..61e591e2fcea6 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -2222,11 +2222,14 @@ impl<'tcx> TyCtxt<'tcx> { self.with_path(id, |path| ast_map::path_to_string(path)) } + /// Returns the `DefPath` of an item. Note that if `id` is not + /// local to this crate -- or is inlined into this crate -- the + /// result will be a non-local `DefPath`. pub fn def_path(&self, id: DefId) -> ast_map::DefPath { if id.is_local() { self.map.def_path(id) } else { - self.sess.cstore.def_path(id) + self.sess.cstore.relative_def_path(id) } } @@ -2236,7 +2239,27 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(id) = self.map.as_local_node_id(id) { self.map.with_path(id, f) } else { - f(self.sess.cstore.item_path(id).iter().cloned().chain(LinkedPath::empty())) + let mut path: Vec<_>; + if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) { + if !extern_crate.direct { + // this comes from some crate that we don't have a direct + // path to; we'll settle for just prepending the name of + // the crate. + path = self.sess.cstore.extern_item_path(id) + } else { + // start with the path to the extern crate, then + // add the relative path to the actual item + fn collector(elems: ast_map::PathElems) -> Vec { + elems.collect() + } + path = self.with_path(extern_crate.def_id, collector); + path.extend(self.sess.cstore.relative_item_path(id)); + } + } else { + // if this was injected, just make a path with name of crate + path = self.sess.cstore.extern_item_path(id); + } + f(path.iter().cloned().chain(LinkedPath::empty())) } } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index c1144387553f0..4fe10aea2e0fb 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -21,7 +21,7 @@ use rustc::back::svh::Svh; use rustc::dep_graph::DepNode; use rustc::session::{config, Session}; use rustc::session::search_paths::PathKind; -use rustc::middle::cstore::{CrateStore, validate_crate_name}; +use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; use rustc::util::nodemap::FnvHashMap; use rustc::front::map as hir_map; @@ -38,7 +38,6 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::errors::FatalError; use syntax::parse::token::InternedString; -use syntax::util::small_vector::SmallVector; use rustc_front::intravisit::Visitor; use rustc_front::hir; use log; @@ -344,15 +343,13 @@ impl<'a> CrateReader<'a> { let cmeta = Rc::new(cstore::crate_metadata { name: name.to_string(), - local_path: RefCell::new(SmallVector::zero()), - local_def_path: RefCell::new(vec![]), + extern_crate: Cell::new(None), index: decoder::load_index(metadata.as_slice()), xref_index: decoder::load_xrefs(metadata.as_slice()), data: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), - span: span, staged_api: staged_api, explicitly_linked: Cell::new(explicitly_linked), }); @@ -386,8 +383,7 @@ impl<'a> CrateReader<'a> { span: Span, kind: PathKind, explicitly_linked: bool) - -> (ast::CrateNum, Rc, - cstore::CrateSource) { + -> (ast::CrateNum, Rc, cstore::CrateSource) { enum LookupResult { Previous(ast::CrateNum), Loaded(loader::Library), @@ -444,23 +440,54 @@ impl<'a> CrateReader<'a> { } } + fn update_extern_crate(&mut self, + cnum: ast::CrateNum, + mut extern_crate: ExternCrate) + { + let cmeta = self.cstore.get_crate_data(cnum); + let old_extern_crate = cmeta.extern_crate.get(); + + // Prefer: + // - something over nothing (tuple.0); + // - direct extern crate to indirect (tuple.1); + // - shorter paths to longer (tuple.2). + let new_rank = (true, extern_crate.direct, !extern_crate.path_len); + let old_rank = match old_extern_crate { + None => (false, false, !0), + Some(ref c) => (true, c.direct, !c.path_len), + }; + + if old_rank >= new_rank { + return; // no change needed + } + + cmeta.extern_crate.set(Some(extern_crate)); + + // Propagate the extern crate info to dependencies. + extern_crate.direct = false; + for &dep_cnum in cmeta.cnum_map.borrow().values() { + self.update_extern_crate(dep_cnum, extern_crate); + } + } + // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(&mut self, root: &Option, - cdata: &[u8], span : Span) - -> cstore::cnum_map { + cdata: &[u8], + span : Span) + -> cstore::cnum_map { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers decoder::get_crate_deps(cdata).iter().map(|dep| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); let (local_cnum, _, _) = self.resolve_crate(root, - &dep.name, - &dep.name, - Some(&dep.hash), - span, - PathKind::Dependency, - dep.explicitly_linked); + &dep.name, + &dep.name, + Some(&dep.hash), + span, + PathKind::Dependency, + dep.explicitly_linked); (dep.cnum, local_cnum) }).collect() } @@ -802,19 +829,24 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { match self.creader.extract_crate_info_hir(i) { Some(info) => { - let (cnum, cmeta, _) = self.creader.resolve_crate(&None, - &info.ident, - &info.name, - None, - i.span, - PathKind::Crate, - true); + let (cnum, _, _) = self.creader.resolve_crate(&None, + &info.ident, + &info.name, + None, + i.span, + PathKind::Crate, + true); let def_id = self.ast_map.local_def_id(i.id); - let def_path = self.ast_map.def_path(def_id); - cmeta.update_local_def_path(def_path); - self.ast_map.with_path(i.id, |path| { - cmeta.update_local_path(path) - }); + + let len = self.ast_map.def_path(def_id).data.len(); + + self.creader.update_extern_crate(cnum, + ExternCrate { + def_id: def_id, + span: i.span, + direct: true, + path_len: len, + }); self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } None => () diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index fb4dbbba8da49..25cc2f91753a3 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -13,7 +13,7 @@ use decoder; use encoder; use loader; -use middle::cstore::{CrateStore, CrateSource, ChildItem, FoundAst}; +use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use middle::def; use middle::lang_items; @@ -128,16 +128,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_method_arg_names(&cdata, did.index) } - fn item_path(&self, def: DefId) -> Vec { + fn relative_item_path(&self, def: DefId) -> Vec { let cdata = self.get_crate_data(def.krate); - let path = decoder::get_item_path(&cdata, def.index); - - cdata.with_local_path(|cpath| { - let mut r = Vec::with_capacity(cpath.len() + path.len()); - r.extend_from_slice(cpath); - r.extend_from_slice(&path); - r - }) + decoder::get_item_path(&cdata, def.index) } fn extern_item_path(&self, def: DefId) -> Vec { @@ -344,6 +337,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { token::intern_and_get_ident(&self.get_crate_data(cnum).name()) } + fn extern_crate(&self, cnum: ast::CrateNum) -> Option + { + self.get_crate_data(cnum).extern_crate.get() + } + fn crate_hash(&self, cnum: ast::CrateNum) -> Svh { let cdata = self.get_crate_data(cnum); @@ -383,12 +381,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_reachable_ids(&cdata) } - fn def_path(&self, def: DefId) -> hir_map::DefPath - { + /// Returns the `DefKey` for a given `DefId`. This indicates the + /// parent `DefId` as well as some idea of what kind of data the + /// `DefId` refers to. + fn def_key(&self, def: DefId) -> hir_map::DefKey { + let cdata = self.get_crate_data(def.krate); + decoder::def_key(&cdata, def.index) + } + + fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { let cdata = self.get_crate_data(def.krate); - let path = decoder::def_path(&cdata, def.index); - let local_path = cdata.local_def_path(); - local_path.into_iter().chain(path).collect() + decoder::def_path(&cdata, def.index) } fn variant_kind(&self, def_id: DefId) -> Option { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 17c485c73497f..f092ee3919826 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -21,7 +21,7 @@ use index; use loader; use rustc::back::svh::Svh; -use rustc::front::map as ast_map; +use rustc::middle::cstore::{ExternCrate}; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use std::cell::{RefCell, Ref, Cell}; @@ -31,9 +31,7 @@ use flate::Bytes; use syntax::ast; use syntax::attr; use syntax::codemap; -use syntax::parse::token; use syntax::parse::token::IdentInterner; -use syntax::util::small_vector::SmallVector; pub use middle::cstore::{NativeLibraryKind, LinkagePreference}; pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; @@ -63,13 +61,16 @@ pub struct ImportedFileMap { pub struct crate_metadata { pub name: String, - pub local_path: RefCell>, - pub local_def_path: RefCell, + + /// Information about the extern crate that caused this crate to + /// be loaded. If this is `None`, then the crate was injected + /// (e.g., by the allocator) + pub extern_crate: Cell>, + pub data: MetadataBlob, pub cnum_map: RefCell, pub cnum: ast::CrateNum, pub codemap_import_info: RefCell>, - pub span: codemap::Span, pub staged_api: bool, pub index: index::Index, @@ -268,50 +269,6 @@ impl crate_metadata { } } - pub fn with_local_path(&self, f: F) -> T - where F: Fn(&[ast_map::PathElem]) -> T - { - let cpath = self.local_path.borrow(); - if cpath.is_empty() { - let name = ast_map::PathMod(token::intern(&self.name)); - f(&[name]) - } else { - f(cpath.as_slice()) - } - } - - pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) { - let mut cpath = self.local_path.borrow_mut(); - let cap = cpath.len(); - match cap { - 0 => *cpath = candidate.collect(), - 1 => (), - _ => { - let candidate: SmallVector<_> = candidate.collect(); - if candidate.len() < cap { - *cpath = candidate; - } - }, - } - } - - pub fn local_def_path(&self) -> ast_map::DefPath { - let local_def_path = self.local_def_path.borrow(); - if local_def_path.is_empty() { - let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name)); - vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }] - } else { - local_def_path.clone() - } - } - - pub fn update_local_def_path(&self, candidate: ast_map::DefPath) { - let mut local_def_path = self.local_def_path.borrow_mut(); - if local_def_path.is_empty() || candidate.len() < local_def_path.len() { - *local_def_path = candidate; - } - } - pub fn is_allocator(&self) -> bool { let attrs = decoder::get_crate_attributes(self.data()); attr::contains_name(&attrs, "allocator") diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 562525e956a89..561248fc703f3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1763,7 +1763,9 @@ pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &TyCtxt<'tcx>) .parse_closure_ty() } -fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey { +pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { + debug!("def_key: id={:?}", id); + let item_doc = cdata.lookup_item(id); match reader::maybe_get_doc(item_doc, tag_def_key) { Some(def_key_doc) => { let mut decoder = reader::Decoder::new(def_key_doc); From cd5cf09635c41e3f9b6df79a50c1fb24ee855153 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 05:53:45 -0400 Subject: [PATCH 24/45] add krate_attrs accessor makes better edges in dep graph --- src/librustc/front/map/mod.rs | 11 ++++++++++- src/librustc_trans/trans/debuginfo/gdb.rs | 5 +---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs index a1355046f48c1..6d6f20c70ec4d 100644 --- a/src/librustc/front/map/mod.rs +++ b/src/librustc/front/map/mod.rs @@ -19,7 +19,7 @@ use dep_graph::{DepGraph, DepNode}; use middle::cstore::InlinedItem; use middle::cstore::InlinedItem as II; -use middle::def_id::DefId; +use middle::def_id::{CRATE_DEF_INDEX, DefId}; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID}; @@ -388,6 +388,15 @@ impl<'ast> Map<'ast> { self.forest.krate() } + /// Get the attributes on the krate. This is preferable to + /// invoking `krate.attrs` because it registers a tighter + /// dep-graph access. + pub fn krate_attrs(&self) -> &'ast [ast::Attribute] { + let crate_root_def_id = DefId::local(CRATE_DEF_INDEX); + self.dep_graph.read(DepNode::Hir(crate_root_def_id)); + &self.forest.krate.attrs + } + /// Retrieve the Node corresponding to `id`, panicking if it cannot /// be found. pub fn get(&self, id: NodeId) -> Node<'ast> { diff --git a/src/librustc_trans/trans/debuginfo/gdb.rs b/src/librustc_trans/trans/debuginfo/gdb.rs index 4e3fadd0fa911..7740f2775866c 100644 --- a/src/librustc_trans/trans/debuginfo/gdb.rs +++ b/src/librustc_trans/trans/debuginfo/gdb.rs @@ -90,10 +90,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) pub fn needs_gdb_debug_scripts_section(ccx: &CrateContext) -> bool { let omit_gdb_pretty_printer_section = - attr::contains_name(&ccx.tcx() - .map - .krate() - .attrs, + attr::contains_name(&ccx.tcx().map.krate_attrs(), "omit_gdb_pretty_printer_section"); !omit_gdb_pretty_printer_section && From 2291abf313b1c619a34694e1756ddaf2a5cb34d9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 05:57:03 -0400 Subject: [PATCH 25/45] refactor item-paths in diagnostics, symbol names This change has a few parts. We introduce a new `item_path` module for constructing item paths. The job of this module is basically to make nice, user-readable paths -- but these paths are not necessarily 100% unique. They meant to help a *human* find code, but not necessarily a compute. These paths are used to drive `item_path_str` but also symbol names. Because the paths are not unique, we also modify the symbol name hash to include the full `DefPath`, whereas before it included only those aspects of the def-path that were not included in the "informative" symbol name. Eventually, I'd like to make the item-path infrastructure a bit more declarative. Right now it's based purely on strings. In particular, for impls, we should supply the raw types to the `ItemPathBuffer`, so that symbol names can be encoded using the C++ encoding scheme for better integration with tooling. --- src/librustc/middle/ty/item_path.rs | 317 ++++++++++++++++++++++++ src/librustc/middle/ty/mod.rs | 9 +- src/librustc_trans/back/symbol_names.rs | 62 +++-- 3 files changed, 362 insertions(+), 26 deletions(-) create mode 100644 src/librustc/middle/ty/item_path.rs diff --git a/src/librustc/middle/ty/item_path.rs b/src/librustc/middle/ty/item_path.rs new file mode 100644 index 0000000000000..147230f5bdcd0 --- /dev/null +++ b/src/librustc/middle/ty/item_path.rs @@ -0,0 +1,317 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use front::map::DefPathData; +use middle::cstore::LOCAL_CRATE; +use middle::def_id::DefId; +use middle::ty::{self, Ty, TyCtxt}; +use syntax::ast; + +impl<'tcx> TyCtxt<'tcx> { + /// Returns a string identifying this def-id. This string is + /// suitable for user output. It is relative to the current crate + /// root. + pub fn item_path_str(&self, def_id: DefId) -> String { + let mut buffer = LocalPathBuffer::new(RootMode::Local); + self.push_item_path(&mut buffer, def_id); + buffer.into_string() + } + + /// Returns a string identifying this def-id. This string is + /// suitable for user output. It always begins with a crate identifier. + pub fn absolute_item_path_str(&self, def_id: DefId) -> String { + let mut buffer = LocalPathBuffer::new(RootMode::Absolute); + self.push_item_path(&mut buffer, def_id); + buffer.into_string() + } + + /// Returns the "path" to a particular crate. This can proceed in + /// various ways, depending on the `root_mode` of the `buffer`. + /// (See `RootMode` enum for more details.) + pub fn push_krate_path(&self, buffer: &mut T, cnum: ast::CrateNum) + where T: ItemPathBuffer + { + match *buffer.root_mode() { + RootMode::Local => { + // In local mode, when we encounter a crate other than + // LOCAL_CRATE, execution proceeds in one of two ways: + // + // 1. for a direct dependency, where user added an + // `extern crate` manually, we put the `extern + // crate` as the parent. So you wind up with + // something relative to the current crate. + // 2. for an indirect crate, where there is no extern + // crate, we just prepend the crate name. + // + // Returns `None` for the local crate. + if cnum != LOCAL_CRATE { + let opt_extern_crate = self.sess.cstore.extern_crate(cnum); + let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| { + if extern_crate.direct { + Some(extern_crate.def_id) + } else { + None + } + }); + if let Some(extern_crate_def_id) = opt_extern_crate { + self.push_item_path(buffer, extern_crate_def_id); + } else { + buffer.push(&self.crate_name(cnum)); + } + } + } + RootMode::Absolute => { + // In absolute mode, just write the crate name + // unconditionally. + buffer.push(&self.crate_name(cnum)); + } + } + } + + pub fn push_item_path(&self, buffer: &mut T, def_id: DefId) + where T: ItemPathBuffer + { + let key = self.def_key(def_id); + match key.disambiguated_data.data { + DefPathData::CrateRoot => { + assert!(key.parent.is_none()); + self.push_krate_path(buffer, def_id.krate); + } + + DefPathData::InlinedRoot(ref root_path) => { + assert!(key.parent.is_none()); + self.push_item_path(buffer, root_path.def_id); + } + + DefPathData::Impl => { + self.push_impl_path(buffer, def_id); + } + + // Unclear if there is any value in distinguishing these. + // Probably eventually (and maybe we would even want + // finer-grained distinctions, e.g. between enum/struct). + data @ DefPathData::Misc | + data @ DefPathData::TypeNs(..) | + data @ DefPathData::ValueNs(..) | + data @ DefPathData::TypeParam(..) | + data @ DefPathData::LifetimeDef(..) | + data @ DefPathData::EnumVariant(..) | + data @ DefPathData::Field(..) | + data @ DefPathData::StructCtor | + data @ DefPathData::Initializer | + data @ DefPathData::MacroDef(..) | + data @ DefPathData::ClosureExpr | + data @ DefPathData::Binding(..) => { + let parent_def_id = self.parent_def_id(def_id).unwrap(); + self.push_item_path(buffer, parent_def_id); + buffer.push(&data.as_interned_str()); + } + } + } + + fn push_impl_path(&self, + buffer: &mut T, + impl_def_id: DefId) + where T: ItemPathBuffer + { + let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); + + let use_types = if !impl_def_id.is_local() { + // always have full types available for extern crates + true + } else { + // for local crates, check whether type info is + // available; typeck might not have completed yet + self.impl_trait_refs.borrow().contains_key(&impl_def_id) + }; + + if !use_types { + return self.push_impl_path_fallback(buffer, impl_def_id); + } + + // Decide whether to print the parent path for the impl. + // Logically, since impls are global, it's never needed, but + // users may find it useful. Currently, we omit the parent if + // the impl is either in the same module as the self-type or + // as the trait. + let self_ty = self.lookup_item_type(impl_def_id).ty; + let in_self_mod = match self.characteristic_def_id_of_type(self_ty) { + None => false, + Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), + }; + + let impl_trait_ref = self.impl_trait_ref(impl_def_id); + let in_trait_mod = match impl_trait_ref { + None => false, + Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id), + }; + + if !in_self_mod && !in_trait_mod { + // If the impl is not co-located with either self-type or + // trait-type, then fallback to a format that identifies + // the module more clearly. + self.push_item_path(buffer, parent_def_id); + if let Some(trait_ref) = impl_trait_ref { + buffer.push(&format!("", trait_ref, self_ty)); + } else { + buffer.push(&format!("", self_ty)); + } + return; + } + + // Otherwise, try to give a good form that would be valid language + // syntax. Preferably using associated item notation. + + if let Some(trait_ref) = impl_trait_ref { + // Trait impls. + buffer.push(&format!("<{} as {}>", + self_ty, + trait_ref)); + return; + } + + // Inherent impls. Try to print `Foo::bar` for an inherent + // impl on `Foo`, but fallback to `::bar` if self-type is + // anything other than a simple path. + match self_ty.sty { + ty::TyStruct(adt_def, substs) | + ty::TyEnum(adt_def, substs) => { + if substs.types.is_empty() { // ignore regions + self.push_item_path(buffer, adt_def.did); + } else { + buffer.push(&format!("<{}>", self_ty)); + } + } + + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyStr => { + buffer.push(&format!("{}", self_ty)); + } + + _ => { + buffer.push(&format!("<{}>", self_ty)); + } + } + } + + fn push_impl_path_fallback(&self, + buffer: &mut T, + impl_def_id: DefId) + where T: ItemPathBuffer + { + // If no type info is available, fall back to + // pretty printing some span information. This should + // only occur very early in the compiler pipeline. + let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); + self.push_item_path(buffer, parent_def_id); + let node_id = self.map.as_local_node_id(impl_def_id).unwrap(); + let item = self.map.expect_item(node_id); + let span_str = self.sess.codemap().span_to_string(item.span); + buffer.push(&format!("", span_str)); + } + + /// As a heuristic, when we see an impl, if we see that the + /// 'self-type' is a type defined in the same module as the impl, + /// we can omit including the path to the impl itself. This + /// function tries to find a "characteristic def-id" for a + /// type. It's just a heuristic so it makes some questionable + /// decisions and we may want to adjust it later. + fn characteristic_def_id_of_type(&self, ty: Ty<'tcx>) -> Option { + match ty.sty { + ty::TyStruct(adt_def, _) | + ty::TyEnum(adt_def, _) => + Some(adt_def.did), + + ty::TyTrait(ref data) => + Some(data.principal_def_id()), + + ty::TyBox(subty) => + self.characteristic_def_id_of_type(subty), + + ty::TyRawPtr(mt) | + ty::TyRef(_, mt) => + self.characteristic_def_id_of_type(mt.ty), + + ty::TyTuple(ref tys) => + tys.iter() + .filter_map(|ty| self.characteristic_def_id_of_type(ty)) + .next(), + + _ => + None + } + } + + /// Returns the def-id of `def_id`'s parent in the def tree. If + /// this returns `None`, then `def_id` represents a crate root or + /// inlined root. + fn parent_def_id(&self, def_id: DefId) -> Option { + let key = self.def_key(def_id); + key.parent.map(|index| DefId { krate: def_id.krate, index: index }) + } +} + +/// Unifying Trait for different kinds of item paths we might +/// construct. The basic interface is that components get pushed: the +/// instance can also customize how we handle the root of a crate. +pub trait ItemPathBuffer { + fn root_mode(&self) -> &RootMode; + fn push(&mut self, text: &str); +} + +#[derive(Debug)] +pub enum RootMode { + /// Try to make a path relative to the local crate. In + /// particular, local paths have no prefix, and if the path comes + /// from an extern crate, start with the path to the `extern + /// crate` declaration. + Local, + + /// Always prepend the crate name to the path, forming an absolute + /// path from within a given set of crates. + Absolute, +} + +#[derive(Debug)] +struct LocalPathBuffer { + root_mode: RootMode, + str: String, +} + +impl LocalPathBuffer { + fn new(root_mode: RootMode) -> LocalPathBuffer { + LocalPathBuffer { + root_mode: root_mode, + str: String::new() + } + } + + fn into_string(self) -> String { + self.str + } + +} + +impl ItemPathBuffer for LocalPathBuffer { + fn root_mode(&self) -> &RootMode { + &self.root_mode + } + + fn push(&mut self, text: &str) { + if !self.str.is_empty() { + self.str.push_str("::"); + } + self.str.push_str(text); + } +} diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 61e591e2fcea6..a4c3e82b6335d 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -86,6 +86,7 @@ pub mod cast; pub mod error; pub mod fast_reject; pub mod fold; +pub mod item_path; pub mod _match; pub mod maps; pub mod outlives; @@ -2218,8 +2219,12 @@ impl<'tcx> TyCtxt<'tcx> { self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id() } - pub fn item_path_str(&self, id: DefId) -> String { - self.with_path(id, |path| ast_map::path_to_string(path)) + pub fn def_key(&self, id: DefId) -> ast_map::DefKey { + if id.is_local() { + self.map.def_key(id) + } else { + self.sess.cstore.def_key(id) + } } /// Returns the `DefPath` of an item. Note that if `id` is not diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index a67b6841f02a1..81b00c3827f3c 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -103,10 +103,10 @@ use util::sha2::{Digest, Sha256}; use rustc::middle::cstore; use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, TypeFoldable}; +use rustc::middle::ty::item_path::{ItemPathBuffer, RootMode}; use rustc::front::map::definitions::DefPath; use std::fmt::Write; -use syntax::ast; use syntax::parse::token::{self, InternedString}; use serialize::hex::ToHex; @@ -135,29 +135,23 @@ pub fn def_path_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_path: &DefPath) -> S fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_path: &DefPath, - originating_crate: ast::CrateNum, parameters: &[ty::Ty<'tcx>]) -> String { + debug!("get_symbol_hash(def_path={:?}, parameters={:?})", + def_path, parameters); + let tcx = ccx.tcx(); let mut hash_state = ccx.symbol_hasher().borrow_mut(); hash_state.reset(); - if originating_crate == cstore::LOCAL_CRATE { - hash_state.input_str(&tcx.sess.crate_disambiguator.borrow()[..]); - } else { - hash_state.input_str(&tcx.sess.cstore.crate_disambiguator(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); - } + // the main symbol name is not necessarily unique; hash in the + // compiler's internal def-path, guaranteeing each symbol has a + // truly unique path + hash_state.input_str(&def_path_to_string(tcx, def_path)); + // also include any type parameters (for generic items) for t in parameters { assert!(!t.has_erasable_regions()); assert!(!t.needs_subst()); @@ -180,6 +174,9 @@ fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> String { let &Instance { def: mut def_id, params: parameters } = instance; + debug!("exported_name_with_opt_suffix(def_id={:?}, parameters={:?}, suffix={:?})", + def_id, parameters, suffix); + if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) { def_id = src_def_id; @@ -187,21 +184,34 @@ fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } let def_path = ccx.tcx().def_path(def_id); - let hash = get_symbol_hash(ccx, &def_path, def_id.krate, parameters.as_slice()); + assert_eq!(def_path.krate, def_id.krate); + let hash = get_symbol_hash(ccx, &def_path, parameters.as_slice()); - let mut path = Vec::with_capacity(16); + let mut buffer = SymbolPathBuffer { + names: Vec::with_capacity(def_path.data.len()) + }; + ccx.tcx().push_item_path(&mut buffer, def_id); - if def_id.is_local() { - path.push(ccx.tcx().crate_name.clone()); + if let Some(suffix) = suffix { + buffer.push(suffix); } - path.extend(def_path.into_iter().map(|e| e.data.as_interned_str())); + mangle(buffer.names.into_iter(), Some(&hash[..])) +} - if let Some(suffix) = suffix { - path.push(token::intern_and_get_ident(suffix)); +struct SymbolPathBuffer { + names: Vec, +} + +impl ItemPathBuffer for SymbolPathBuffer { + fn root_mode(&self) -> &RootMode { + const ABSOLUTE: &'static RootMode = &RootMode::Absolute; + ABSOLUTE } - mangle(path.into_iter(), Some(&hash[..])) + fn push(&mut self, text: &str) { + self.names.push(token::intern(text).as_str()); + } } pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -225,7 +235,11 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx> -> 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]); + let def_path = DefPath { + data: vec![], + krate: cstore::LOCAL_CRATE, + }; + let hash = get_symbol_hash(ccx, &def_path, &[t]); mangle(path.iter().cloned(), Some(&hash[..])) } From 977636156a931e9716ae681d06b1b24477a87f43 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 15:00:20 -0400 Subject: [PATCH 26/45] unit-test symbol-names and item-paths --- src/librustc_trans/trans/base.rs | 3 + src/librustc_trans/trans/mod.rs | 1 + src/librustc_trans/trans/symbol_names_test.rs | 84 +++++++++++++++++++ src/libsyntax/feature_gate.rs | 7 ++ src/test/compile-fail/symbol-names/basic.rs | 16 ++++ src/test/compile-fail/symbol-names/impl1.rs | 35 ++++++++ 6 files changed, 146 insertions(+) create mode 100644 src/librustc_trans/trans/symbol_names_test.rs create mode 100644 src/test/compile-fail/symbol-names/basic.rs create mode 100644 src/test/compile-fail/symbol-names/impl1.rs diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 160596683f1c2..85f3bed52544a 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -85,6 +85,7 @@ use trans::machine::{llalign_of_min, llsize_of, llsize_of_real}; use trans::meth; use trans::mir; use trans::monomorphize::{self, Instance}; +use trans::symbol_names_test; use trans::tvec; use trans::type_::Type; use trans::type_of; @@ -2758,6 +2759,8 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, } collector::print_collection_results(&ccx); + + symbol_names_test::report_symbol_names(&ccx); } emit_link_guard_if_necessary(&shared_ccx); diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index 2e71128a1e78b..5c38de99da355 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -60,6 +60,7 @@ mod meth; mod mir; mod monomorphize; mod collector; +mod symbol_names_test; mod tvec; mod type_; mod type_of; diff --git a/src/librustc_trans/trans/symbol_names_test.rs b/src/librustc_trans/trans/symbol_names_test.rs new file mode 100644 index 0000000000000..2b3faa3786e35 --- /dev/null +++ b/src/librustc_trans/trans/symbol_names_test.rs @@ -0,0 +1,84 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Walks the crate looking for items/impl-items/trait-items that have +//! either a `rustc_symbol_name` or `rustc_item_path` attribute and +//! generates an error giving, respectively, the symbol name or +//! item-path. This is used for unit testing the code that generates +//! paths etc in all kinds of annoying scenarios. + +use back::symbol_names; +use rustc::middle::ty::TyCtxt; +use rustc_front::hir; +use rustc_front::intravisit::{self, Visitor}; +use syntax::ast; +use syntax::attr::AttrMetaMethods; +use trans::common::CrateContext; + +const SYMBOL_NAME: &'static str = "rustc_symbol_name"; +const ITEM_PATH: &'static str = "rustc_item_path"; + +pub fn report_symbol_names(ccx: &CrateContext) { + // if the `rustc_attrs` feature is not enabled, then the + // attributes we are interested in cannot be present anyway, so + // skip the walk. + let tcx = ccx.tcx(); + if !tcx.sess.features.borrow().rustc_attrs { + return; + } + + let _ignore = tcx.dep_graph.in_ignore(); + let mut visitor = SymbolNamesTest { ccx: ccx, tcx: tcx }; + tcx.map.krate().visit_all_items(&mut visitor); +} + +struct SymbolNamesTest<'a, 'tcx:'a> { + ccx: &'a CrateContext<'a, 'tcx>, + tcx: &'a TyCtxt<'tcx>, +} + +impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { + fn process_attrs(&mut self, + node_id: ast::NodeId) { + let def_id = self.tcx.map.local_def_id(node_id); + for attr in self.tcx.get_attrs(def_id).iter() { + if attr.check_name(SYMBOL_NAME) { + // for now, just monomorphic names + let name = symbol_names::exported_name(self.ccx, def_id, &[]); + self.tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); + } else if attr.check_name(ITEM_PATH) { + let path = self.tcx.item_path_str(def_id); + self.tcx.sess.span_err(attr.span, &format!("item-path({})", path)); + } + + // (*) The formatting of `tag({})` is chosen so that tests can elect + // to test the entirety of the string, if they choose, or else just + // some subset. + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> { + fn visit_item(&mut self, item: &'tcx hir::Item) { + self.process_attrs(item.id); + intravisit::walk_item(self, item); + } + + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { + self.process_attrs(ti.id); + intravisit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { + self.process_attrs(ii.id); + intravisit::walk_impl_item(self, ii) + } +} + diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 299b7d8b9ba07..80e1ae111a2d8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -349,6 +349,10 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat "the `#[rustc_if_this_changed]` attribute \ is just used for rustc unit tests \ and will never be stable")), + ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs", + "internal rustc attributes will never be stable")), + ("rustc_item_path", Whitelisted, Gated("rustc_attrs", + "internal rustc attributes will never be stable")), ("rustc_move_fragments", Normal, Gated("rustc_attrs", "the `#[rustc_move_fragments]` attribute \ is just used for rustc unit tests \ @@ -579,6 +583,7 @@ pub struct Features { pub const_indexing: bool, pub static_recursion: bool, pub default_type_parameter_fallback: bool, + pub rustc_attrs: bool, pub type_macros: bool, pub cfg_target_feature: bool, pub cfg_target_vendor: bool, @@ -614,6 +619,7 @@ impl Features { const_indexing: false, static_recursion: false, default_type_parameter_fallback: false, + rustc_attrs: false, type_macros: false, cfg_target_feature: false, cfg_target_vendor: false, @@ -1225,6 +1231,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, const_indexing: cx.has_feature("const_indexing"), static_recursion: cx.has_feature("static_recursion"), default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), + rustc_attrs: cx.has_feature("rustc_attrs"), type_macros: cx.has_feature("type_macros"), cfg_target_feature: cx.has_feature("cfg_target_feature"), cfg_target_vendor: cx.has_feature("cfg_target_vendor"), diff --git a/src/test/compile-fail/symbol-names/basic.rs b/src/test/compile-fail/symbol-names/basic.rs new file mode 100644 index 0000000000000..0095774fcb8d2 --- /dev/null +++ b/src/test/compile-fail/symbol-names/basic.rs @@ -0,0 +1,16 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +#[rustc_symbol_name] //~ ERROR _ZN5basic4main +#[rustc_item_path] //~ ERROR item-path(main) +fn main() { +} diff --git a/src/test/compile-fail/symbol-names/impl1.rs b/src/test/compile-fail/symbol-names/impl1.rs new file mode 100644 index 0000000000000..39bee26da20b8 --- /dev/null +++ b/src/test/compile-fail/symbol-names/impl1.rs @@ -0,0 +1,35 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod foo { + pub struct Foo { x: u32 } + + impl Foo { + #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar + #[rustc_item_path] //~ ERROR item-path(foo::Foo::bar) + fn bar() { } + } +} + +mod bar { + use foo::Foo; + + impl Foo { + #[rustc_symbol_name] //~ ERROR _ZN5impl13bar26_$LT$impl$u20$foo..Foo$GT$3baz + #[rustc_item_path] //~ ERROR item-path(bar::::baz) + fn baz() { } + } +} + +fn main() { +} From 86fa58d6c86360c9b98dbb8bfc6c3f65447f9d4c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 15:00:34 -0400 Subject: [PATCH 27/45] remove unused variable in compiletest --- src/compiletest/compiletest.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 51bc9d71f883c..6c6a78a360b9e 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -126,12 +126,6 @@ pub fn parse_config(args: Vec ) -> Config { } } - let filter = if !matches.free.is_empty() { - Some(matches.free[0].clone()) - } else { - None - }; - Config { compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), From af057bdb1cab90764dff895952ecf34eaffe6b5e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 16 Mar 2016 16:37:19 -0400 Subject: [PATCH 28/45] renumber diagnostic to avoid conflict specialization nabbed E0520 --- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/diagnostics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4fe10aea2e0fb..2318dc161fc0d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -298,7 +298,7 @@ impl<'a> CrateReader<'a> { 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, + span_fatal!(self.sess, span, E0521, "found two different crates with name `{}` that are \ not distinguished by differing `-C metadata`. This \ will result in symbol conflicts between the two.", diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index ebc7a4b461e68..7c9eff3062985 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -88,5 +88,5 @@ register_diagnostics! { 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 + E0521, // two dependencies have same (crate-name, disambiguator) but different SVH } From 5a681162400b913eaa75eb8de5868db587f4fa35 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Mar 2016 05:32:04 -0400 Subject: [PATCH 29/45] pacify the merciless tidy: s/E0521/E0522 Gah. I always find it confusing that make tidy gives me the highest error code, but not the **next** error code. --- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/diagnostics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 2318dc161fc0d..7965228d43bef 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -298,7 +298,7 @@ impl<'a> CrateReader<'a> { 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, E0521, + span_fatal!(self.sess, span, E0522, "found two different crates with name `{}` that are \ not distinguished by differing `-C metadata`. This \ will result in symbol conflicts between the two.", diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 7c9eff3062985..ea6e4b57bbae7 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -88,5 +88,5 @@ register_diagnostics! { E0469, // imported macro not found E0470, // reexported macro not found E0519, // local crate and dependency have same (crate-name, disambiguator) - E0521, // two dependencies have same (crate-name, disambiguator) but different SVH + E0522, // two dependencies have same (crate-name, disambiguator) but different SVH } From e8dfaa71e6a6d9b415011ca4d59e9ab498584e73 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 Mar 2016 13:11:42 -0400 Subject: [PATCH 30/45] Correections due to refactoring . --- src/librustc_metadata/decoder.rs | 4 ++-- src/librustc_trans/trans/link_guard.rs | 21 ++++++++++--------- src/librustc_trans/trans/symbol_names_test.rs | 6 ++++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 561248fc703f3..a4eeee44fb718 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -810,7 +810,7 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &TyCtxt<'tcx>, id: DefIndex) let mut parent_path = item_path(item_doc); parent_path.pop(); let mut parent_def_path = def_path(cdata, id); - parent_def_path.pop(); + parent_def_path.data.pop(); if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) { let ii = decode_inlined_item(cdata, tcx, @@ -830,7 +830,7 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &TyCtxt<'tcx>, id: DefIndex) let mut grandparent_path = parent_path; grandparent_path.pop(); let mut grandparent_def_path = parent_def_path; - grandparent_def_path.pop(); + grandparent_def_path.data.pop(); let parent_doc = cdata.lookup_item(parent_did.index); if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, tag_ast as usize) { let ii = decode_inlined_item(cdata, diff --git a/src/librustc_trans/trans/link_guard.rs b/src/librustc_trans/trans/link_guard.rs index 94606cafce5de..453afa827e8f1 100644 --- a/src/librustc_trans/trans/link_guard.rs +++ b/src/librustc_trans/trans/link_guard.rs @@ -49,12 +49,11 @@ pub fn get_or_insert_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) } 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."); - }); + if declare::get_defined_value(ccx, &guard_name[..]).is_some() { + ccx.sess().bug( + &format!("Link guard already defined")); + } + let guard_function = declare::declare_cfn(ccx, &guard_name[..], llfty); attributes::emit_uwtable(guard_function, true); attributes::unwind(guard_function, false); @@ -76,10 +75,12 @@ pub fn get_or_insert_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) let dependency_guard_name = link_guard_name(&crate_name[..], &svh); - let decl = declare::declare_cfn(ccx, - &dependency_guard_name[..], - llfty, - ccx.tcx().mk_nil()); + if declare::get_defined_value(ccx, &dependency_guard_name[..]).is_some() { + ccx.sess().bug( + &format!("Link guard already defined for dependency `{}`", + crate_name)); + } + let decl = declare::declare_cfn(ccx, &dependency_guard_name[..], llfty); attributes::unwind(decl, false); llvm::LLVMPositionBuilderAtEnd(bld, llbb); diff --git a/src/librustc_trans/trans/symbol_names_test.rs b/src/librustc_trans/trans/symbol_names_test.rs index 2b3faa3786e35..63abbfd53b6fa 100644 --- a/src/librustc_trans/trans/symbol_names_test.rs +++ b/src/librustc_trans/trans/symbol_names_test.rs @@ -21,6 +21,7 @@ use rustc_front::intravisit::{self, Visitor}; use syntax::ast; use syntax::attr::AttrMetaMethods; use trans::common::CrateContext; +use trans::monomorphize::Instance; const SYMBOL_NAME: &'static str = "rustc_symbol_name"; const ITEM_PATH: &'static str = "rustc_item_path"; @@ -50,8 +51,9 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { let def_id = self.tcx.map.local_def_id(node_id); for attr in self.tcx.get_attrs(def_id).iter() { if attr.check_name(SYMBOL_NAME) { - // for now, just monomorphic names - let name = symbol_names::exported_name(self.ccx, def_id, &[]); + // for now, can only use on monomorphic names + let instance = Instance::mono(self.tcx, def_id); + let name = symbol_names::exported_name(self.ccx, &instance); self.tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); } else if attr.check_name(ITEM_PATH) { let path = self.tcx.item_path_str(def_id); From bca94230f333bce1f6c480673b5c13c40832b061 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 Mar 2016 15:11:23 -0400 Subject: [PATCH 31/45] Fix accursed issue-4264.pp --- src/test/pretty/issue-4264.pp | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index fedb68a26afc9..fe4337eedc63d 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -41,37 +41,37 @@ ((::std::fmt::format as fn(core::fmt::Arguments<'_>) -> collections::string::String {collections::fmt::format})(((::std::fmt::Arguments::new_v1 as - fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a><'_>::new_v1})(({ - static __STATIC_FMTSTR: - &'static [&'static str] - = - (&([("test" - as - &'static str)] - as - [&'static str; 1]) + fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'_>::new_v1})(({ + static __STATIC_FMTSTR: + &'static [&'static str] + = + (&([("test" as - &'static [&'static str; 1]); - (__STATIC_FMTSTR - as - &'static [&'static str]) - } - as - &[&str]), - (&(match (() - as - ()) - { - () - => - ([] + &'static str)] as - [core::fmt::ArgumentV1<'_>; 0]), - } - as - [core::fmt::ArgumentV1<'_>; 0]) - as - &[core::fmt::ArgumentV1<'_>; 0])) + [&'static str; 1]) + as + &'static [&'static str; 1]); + (__STATIC_FMTSTR + as + &'static [&'static str]) + } + as + &[&str]), + (&(match (() + as + ()) + { + () + => + ([] + as + [core::fmt::ArgumentV1<'_>; 0]), + } + as + [core::fmt::ArgumentV1<'_>; 0]) + as + &[core::fmt::ArgumentV1<'_>; 0])) as core::fmt::Arguments<'_>)) as collections::string::String); From 7e8e6712b5ad07a47ccd8d84fd5112451a76789c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 21 Mar 2016 15:13:40 -0400 Subject: [PATCH 32/45] Remove static linking hack since we are now passing absolute paths --- src/test/run-pass/command-before-exec.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/run-pass/command-before-exec.rs b/src/test/run-pass/command-before-exec.rs index 7c5a21911dbfb..16560637b6926 100644 --- a/src/test/run-pass/command-before-exec.rs +++ b/src/test/run-pass/command-before-exec.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-windows - this is a unix-specific test -// no-prefer-dynamic - this test breaks with dynamic linking as -// some LD_LIBRARY_PATH entries are relative and it cd's to /. #![feature(process_exec, libc)] From b184d2712feb3cf5d7becb1808ef969feb058836 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Mar 2016 11:54:22 -0400 Subject: [PATCH 33/45] check only that symbol names are deterministic Full binary reproducible builds are not possible on all platforms because linker injects a certain amount of randomness, apparently. Or, at minimum, they don't work reliably yet. --- src/test/run-make/reproducible-build/Makefile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/test/run-make/reproducible-build/Makefile b/src/test/run-make/reproducible-build/Makefile index 7447024ee43b1..8e799ca1a4303 100644 --- a/src/test/run-make/reproducible-build/Makefile +++ b/src/test/run-make/reproducible-build/Makefile @@ -3,12 +3,18 @@ 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 + nm "$(TMPDIR)/reproducible-build1" | sort > "$(TMPDIR)/reproducible-build1.nm" + nm "$(TMPDIR)/reproducible-build2" | sort > "$(TMPDIR)/reproducible-build2.nm" + cmp "$(TMPDIR)/reproducible-build1.nm" "$(TMPDIR)/reproducible-build2.nm" || exit 1 $(RUSTC) reproducible-build-aux.rs -g $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build1-debug" $(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build2-debug" - cmp "$(TMPDIR)/reproducible-build1-debug" "$(TMPDIR)/reproducible-build2-debug" || exit 1 + nm "$(TMPDIR)/reproducible-build1-debug" | sort > "$(TMPDIR)/reproducible-build1-debug.nm" + nm "$(TMPDIR)/reproducible-build2-debug" | sort > "$(TMPDIR)/reproducible-build2-debug.nm" + cmp "$(TMPDIR)/reproducible-build1-debug.nm" "$(TMPDIR)/reproducible-build2-debug.nm" || exit 1 $(RUSTC) reproducible-build-aux.rs -O $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build1-opt" $(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build2-opt" - cmp "$(TMPDIR)/reproducible-build1-opt" "$(TMPDIR)/reproducible-build2-opt" || exit 1 + nm "$(TMPDIR)/reproducible-build1-opt" | sort > "$(TMPDIR)/reproducible-build1-opt.nm" + nm "$(TMPDIR)/reproducible-build2-opt" | sort > "$(TMPDIR)/reproducible-build2-opt.nm" + cmp "$(TMPDIR)/reproducible-build1-opt.nm" "$(TMPDIR)/reproducible-build2-opt.nm" || exit 1 From 751c24d345cd016429583e4d6654538ed881748a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Mar 2016 12:18:30 -0400 Subject: [PATCH 34/45] renumber error from E0522 to E0523 another name was added in the meantime --- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/diagnostics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7965228d43bef..d07179749d9ab 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -298,7 +298,7 @@ impl<'a> CrateReader<'a> { 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, E0522, + span_fatal!(self.sess, span, E0523, "found two different crates with name `{}` that are \ not distinguished by differing `-C metadata`. This \ will result in symbol conflicts between the two.", diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index ea6e4b57bbae7..8fa23de9a2d16 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -88,5 +88,5 @@ register_diagnostics! { E0469, // imported macro not found E0470, // reexported macro not found E0519, // local crate and dependency have same (crate-name, disambiguator) - E0522, // two dependencies have same (crate-name, disambiguator) but different SVH + E0523, // two dependencies have same (crate-name, disambiguator) but different SVH } From b385ce12232a6c192b168b75ec9867a5a83d2036 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Mar 2016 20:32:08 -0400 Subject: [PATCH 35/45] workarounds to make link guards work on windows Link guards cause problems in some specific scenarios on windows because they force libcore to be instantiated, since we do not GC functions effectively on windows. The changes here are two: 1. disable core for rsbegin/rsend 2. make panic_fmt an extern fn for smallest-hello-world so that it is not marked as "internal" for LLVM --- src/rtstartup/rsbegin.rs | 13 ++++++++++++- src/rtstartup/rsend.rs | 7 ++++++- src/test/run-pass/smallest-hello-world.rs | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index d1b6fe6655ac6..bbabed20ec1cd 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -23,9 +23,20 @@ // of other runtime components (registered via yet another special image section). #![crate_type="rlib"] -#![no_std] +#![feature(no_core, lang_items, optin_builtin_traits)] +#![no_core] #![allow(non_camel_case_types)] +#[lang="sized"] +trait Sized {} + +#[lang="copy"] +trait Copy {} + +#[lang="sync"] +trait Sync {} +impl Sync for .. {} + #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames { diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs index 5e4e13ebd05e4..1ab194d5eb9ed 100644 --- a/src/rtstartup/rsend.rs +++ b/src/rtstartup/rsend.rs @@ -11,7 +11,12 @@ // See rsbegin.rs for details. #![crate_type="rlib"] -#![no_std] +#![feature(no_core, lang_items, optin_builtin_traits)] +#![no_core] + +#[lang="sync"] +trait Sync {} +impl Sync for .. {} #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs index b11970560d59a..7fc6e6ba1b00a 100644 --- a/src/test/run-pass/smallest-hello-world.rs +++ b/src/test/run-pass/smallest-hello-world.rs @@ -22,7 +22,7 @@ extern "rust-intrinsic" { fn transmute(t: T) -> U; } #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +#[lang = "panic_fmt"] extern fn panic_fmt() -> ! { loop {} } #[no_mangle] pub extern fn rust_eh_register_frames () {} #[no_mangle] pub extern fn rust_eh_unregister_frames () {} From 4c527457f147881dc864b8b737c4288540b32208 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 Mar 2016 10:03:22 -0400 Subject: [PATCH 36/45] rip out link guards As discussed in https://github.com/rust-lang/rust/pull/32293#issuecomment-200597130, adding link guards are a heuristic that is causing undue complications: - the link guards inject extra public symbols, which is not always OK. - link guards as implemented could be a non-trivial performance hit, because no attempt is made to "de-duplicate" the dependency graph, so at worst you have O(N!) calls to the link guard functions. Nonetheless, link guards are very helpful in detecting errors, so it may be worth adding them back in some modified form in the future. --- src/librustc_trans/back/linker.rs | 20 ----- src/librustc_trans/trans/base.rs | 24 ----- src/librustc_trans/trans/link_guard.rs | 117 ------------------------- src/librustc_trans/trans/mod.rs | 1 - 4 files changed, 162 deletions(-) delete mode 100644 src/librustc_trans/trans/link_guard.rs diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 934e0e16a9688..c6576b7fe0d97 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -23,7 +23,6 @@ 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. @@ -361,25 +360,6 @@ impl<'a> Linker for MsvcLinker<'a> { 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 85f3bed52544a..7231304ec4c4f 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -79,7 +79,6 @@ use trans::expr; use trans::glue; use trans::inline; use trans::intrinsic; -use trans::link_guard; use trans::machine; use trans::machine::{llalign_of_min, llsize_of, llsize_of_real}; use trans::meth; @@ -2384,7 +2383,6 @@ 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 { @@ -2763,8 +2761,6 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>, symbol_names_test::report_symbol_names(&ccx); } - emit_link_guard_if_necessary(&shared_ccx); - for ccx in shared_ccx.iter() { if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); @@ -2825,8 +2821,6 @@ 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 @@ -2870,24 +2864,6 @@ 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 deleted file mode 100644 index 453afa827e8f1..0000000000000 --- a/src/librustc_trans/trans/link_guard.rs +++ /dev/null @@ -1,117 +0,0 @@ -// 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)); - if declare::get_defined_value(ccx, &guard_name[..]).is_some() { - ccx.sess().bug( - &format!("Link guard already defined")); - } - let guard_function = declare::declare_cfn(ccx, &guard_name[..], llfty); - - 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); - - if declare::get_defined_value(ccx, &dependency_guard_name[..]).is_some() { - ccx.sess().bug( - &format!("Link guard already defined for dependency `{}`", - crate_name)); - } - let decl = declare::declare_cfn(ccx, &dependency_guard_name[..], llfty); - 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 5c38de99da355..930f37ce25634 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -53,7 +53,6 @@ mod expr; mod glue; mod inline; mod intrinsic; -pub mod link_guard; mod machine; mod _match; mod meth; From 814477a8935bb2ee666cc74f861e21cd4d1fa57a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 Mar 2016 10:03:50 -0400 Subject: [PATCH 37/45] Revert "workarounds to make link guards work on windows" This reverts commit b52004d202ddfffa100d4963216e1673a0be0b95. --- src/rtstartup/rsbegin.rs | 13 +------------ src/rtstartup/rsend.rs | 7 +------ src/test/run-pass/smallest-hello-world.rs | 2 +- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index bbabed20ec1cd..d1b6fe6655ac6 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -23,20 +23,9 @@ // of other runtime components (registered via yet another special image section). #![crate_type="rlib"] -#![feature(no_core, lang_items, optin_builtin_traits)] -#![no_core] +#![no_std] #![allow(non_camel_case_types)] -#[lang="sized"] -trait Sized {} - -#[lang="copy"] -trait Copy {} - -#[lang="sync"] -trait Sync {} -impl Sync for .. {} - #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames { diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs index 1ab194d5eb9ed..5e4e13ebd05e4 100644 --- a/src/rtstartup/rsend.rs +++ b/src/rtstartup/rsend.rs @@ -11,12 +11,7 @@ // See rsbegin.rs for details. #![crate_type="rlib"] -#![feature(no_core, lang_items, optin_builtin_traits)] -#![no_core] - -#[lang="sync"] -trait Sync {} -impl Sync for .. {} +#![no_std] #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs index 7fc6e6ba1b00a..b11970560d59a 100644 --- a/src/test/run-pass/smallest-hello-world.rs +++ b/src/test/run-pass/smallest-hello-world.rs @@ -22,7 +22,7 @@ extern "rust-intrinsic" { fn transmute(t: T) -> U; } #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} -#[lang = "panic_fmt"] extern fn panic_fmt() -> ! { loop {} } +#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } #[no_mangle] pub extern fn rust_eh_register_frames () {} #[no_mangle] pub extern fn rust_eh_unregister_frames () {} From 87debd93285e5527d17ed89ba6930fec5fd3f263 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 Mar 2016 13:19:36 -0400 Subject: [PATCH 38/45] include the immediate type in the symbol name hash the intention is to give some simple protection like link-guards but not impede ability to upgrade dylib in place --- src/librustc_trans/back/symbol_names.rs | 55 +++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 81b00c3827f3c..13a82c0baaa26 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -104,7 +104,7 @@ use rustc::middle::cstore; use rustc::middle::def_id::DefId; use rustc::middle::ty::{self, TypeFoldable}; use rustc::middle::ty::item_path::{ItemPathBuffer, RootMode}; -use rustc::front::map::definitions::DefPath; +use rustc::front::map::definitions::{DefPath, DefPathData}; use std::fmt::Write; use syntax::parse::token::{self, InternedString}; @@ -134,7 +134,18 @@ pub fn def_path_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_path: &DefPath) -> S } fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + + // path to the item this name is for def_path: &DefPath, + + // type of the item, without any generic + // parameters substituted; this is + // included in the hash as a kind of + // safeguard. + item_type: ty::Ty<'tcx>, + + // values for generic type parameters, + // if any. parameters: &[ty::Ty<'tcx>]) -> String { debug!("get_symbol_hash(def_path={:?}, parameters={:?})", @@ -151,6 +162,13 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // truly unique path hash_state.input_str(&def_path_to_string(tcx, def_path)); + // Include the main item-type. Note that, in this case, the + // assertions about `needs_subst` may not hold, but this item-type + // ought to be the same for every reference anyway. + assert!(!item_type.has_erasable_regions()); + let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string); + hash_state.input(&encoded_item_type[..]); + // also include any type parameters (for generic items) for t in parameters { assert!(!t.has_erasable_regions()); @@ -185,7 +203,38 @@ fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let def_path = ccx.tcx().def_path(def_id); assert_eq!(def_path.krate, def_id.krate); - let hash = get_symbol_hash(ccx, &def_path, parameters.as_slice()); + + // We want to compute the "type" of this item. Unfortunately, some + // kinds of items (e.g., closures) don't have an entry in the + // item-type array. So walk back up the find the closest parent + // that DOES have an entry. + let mut ty_def_id = def_id; + let instance_ty; + loop { + let key = ccx.tcx().def_key(ty_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) | + DefPathData::ValueNs(_) => { + instance_ty = ccx.tcx().lookup_item_type(ty_def_id); + break; + } + _ => { + // if we're making a symbol for something, there ought + // to be a value or type-def or something in there + // *somewhere* + ty_def_id.index = key.parent.unwrap_or_else(|| { + panic!("finding type for {:?}, encountered def-id {:?} with no \ + parent", def_id, ty_def_id); + }); + } + } + } + + // Erase regions because they may not be deterministic when hashed + // and should not matter anyhow. + let instance_ty = ccx.tcx().erase_regions(&instance_ty.ty); + + let hash = get_symbol_hash(ccx, &def_path, instance_ty, parameters.as_slice()); let mut buffer = SymbolPathBuffer { names: Vec::with_capacity(def_path.data.len()) @@ -239,7 +288,7 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx> data: vec![], krate: cstore::LOCAL_CRATE, }; - let hash = get_symbol_hash(ccx, &def_path, &[t]); + let hash = get_symbol_hash(ccx, &def_path, t, &[]); mangle(path.iter().cloned(), Some(&hash[..])) } From ab0a87243e9bb97355cb0e4f53b2156cd68207fe Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 Mar 2016 13:20:08 -0400 Subject: [PATCH 39/45] test for immediate symbol name hashing --- src/test/run-make/a-b-a-linker-guard/Makefile | 7 +++++++ src/test/run-make/a-b-a-linker-guard/a.rs | 10 ++++++++++ src/test/run-make/a-b-a-linker-guard/b.rs | 7 +++++++ 3 files changed, 24 insertions(+) create mode 100644 src/test/run-make/a-b-a-linker-guard/Makefile create mode 100644 src/test/run-make/a-b-a-linker-guard/a.rs create mode 100644 src/test/run-make/a-b-a-linker-guard/b.rs diff --git a/src/test/run-make/a-b-a-linker-guard/Makefile b/src/test/run-make/a-b-a-linker-guard/Makefile new file mode 100644 index 0000000000000..4a1b87de88d01 --- /dev/null +++ b/src/test/run-make/a-b-a-linker-guard/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: + $(RUSTC) a.rs --cfg x -C prefer-dynamic + $(RUSTC) b.rs -C prefer-dynamic + $(RUSTC) a.rs --cfg y -C prefer-dynamic + $(call RUN,b) 2>&1 | grep "undefined symbol" diff --git a/src/test/run-make/a-b-a-linker-guard/a.rs b/src/test/run-make/a-b-a-linker-guard/a.rs new file mode 100644 index 0000000000000..f2511b044b500 --- /dev/null +++ b/src/test/run-make/a-b-a-linker-guard/a.rs @@ -0,0 +1,10 @@ +#![crate_name = "a"] +#![crate_type = "dylib"] + +#[cfg(x)] +pub fn foo(x: u32) { } + +#[cfg(y)] +pub fn foo(x: i32) { } + + diff --git a/src/test/run-make/a-b-a-linker-guard/b.rs b/src/test/run-make/a-b-a-linker-guard/b.rs new file mode 100644 index 0000000000000..f30df120a3ba7 --- /dev/null +++ b/src/test/run-make/a-b-a-linker-guard/b.rs @@ -0,0 +1,7 @@ +#![crate_name = "b"] + +extern crate a; + +fn main() { + a::foo(22_u32); +} From fd25a63ba9e2b81e40889e4e9ff3fe355e933cb5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 Mar 2016 13:24:04 -0400 Subject: [PATCH 40/45] document test, don't use grep --- src/test/run-make/a-b-a-linker-guard/Makefile | 7 ++++++- src/test/run-make/a-b-a-linker-guard/a.rs | 10 ++++++++++ src/test/run-make/a-b-a-linker-guard/b.rs | 10 ++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/test/run-make/a-b-a-linker-guard/Makefile b/src/test/run-make/a-b-a-linker-guard/Makefile index 4a1b87de88d01..0962ebfbff546 100644 --- a/src/test/run-make/a-b-a-linker-guard/Makefile +++ b/src/test/run-make/a-b-a-linker-guard/Makefile @@ -1,7 +1,12 @@ -include ../tools.mk +# Test that if we build `b` against a version of `a` that has one set +# of types, it will not run with a dylib that has a different set of +# types. + all: $(RUSTC) a.rs --cfg x -C prefer-dynamic $(RUSTC) b.rs -C prefer-dynamic + $(call RUN,b) $(RUSTC) a.rs --cfg y -C prefer-dynamic - $(call RUN,b) 2>&1 | grep "undefined symbol" + $(call FAIL,b) diff --git a/src/test/run-make/a-b-a-linker-guard/a.rs b/src/test/run-make/a-b-a-linker-guard/a.rs index f2511b044b500..e6cbe2e64d0e9 100644 --- a/src/test/run-make/a-b-a-linker-guard/a.rs +++ b/src/test/run-make/a-b-a-linker-guard/a.rs @@ -1,3 +1,13 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![crate_name = "a"] #![crate_type = "dylib"] diff --git a/src/test/run-make/a-b-a-linker-guard/b.rs b/src/test/run-make/a-b-a-linker-guard/b.rs index f30df120a3ba7..89fd48de5bbf9 100644 --- a/src/test/run-make/a-b-a-linker-guard/b.rs +++ b/src/test/run-make/a-b-a-linker-guard/b.rs @@ -1,3 +1,13 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![crate_name = "b"] extern crate a; From 24059f74d7669634dedc409293a0635f16c6ae76 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Mar 2016 12:48:30 -0400 Subject: [PATCH 41/45] Drive-by fix for unnecessary `&mut` --- src/librustc/middle/traits/fulfill.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 937196b5e8e7a..b2ba8a7a5f99f 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -398,7 +398,7 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, // purposes of the ancestor check, we retain // the invariant that all type variables are // fully refreshed. - if !(&mut is_ancestor)(&obligation.predicate) { + if !is_ancestor(&obligation.predicate) { return None; } } From 8a7b1bca045b3b582f53337799b90a9309adc96b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Mar 2016 12:48:47 -0400 Subject: [PATCH 42/45] Update backtrace test for FIXME on windows --- src/test/run-pass/backtrace.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 88c5fb2c40891..75f057e1e1d8f 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -51,13 +51,30 @@ fn template(me: &str) -> Command { return m; } +fn expected(fn_name: &str) -> String { + // FIXME(#32481) + // + // On windows, we read the function name from debuginfo using some + // system APIs. For whatever reason, these APIs seem to use the + // "name" field, which is only the "relative" name, not the full + // name with namespace info, so we just see `foo` and not + // `backtrace::foo` as we see on linux (which uses the linkage + // name). + + if cfg!(windows) { + format!(" - {}", fn_name) + } else { + format!(" - backtrace::{}", fn_name) + } +} + fn runtest(me: &str) { // Make sure that the stack trace is printed let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); let s = str::from_utf8(&out.stderr).unwrap(); - assert!(s.contains("stack backtrace") && s.contains(" - backtrace::foo"), + assert!(s.contains("stack backtrace") && s.contains(&expected("foo")), "bad output: {}", s); // Make sure the stack trace is *not* printed @@ -67,7 +84,7 @@ fn runtest(me: &str) { let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); let s = str::from_utf8(&out.stderr).unwrap(); - assert!(!s.contains("stack backtrace") && !s.contains(" - backtrace::foo"), + assert!(!s.contains("stack backtrace") && !s.contains(&expected("foo")), "bad output2: {}", s); // Make sure a stack trace is printed @@ -77,7 +94,7 @@ fn runtest(me: &str) { let s = str::from_utf8(&out.stderr).unwrap(); // loosened the following from double::h to double:: due to // spurious failures on mac, 32bit, optimized - assert!(s.contains("stack backtrace") && s.contains(" - backtrace::double"), + assert!(s.contains("stack backtrace") && s.contains(&expected("double")), "bad output3: {}", s); // Make sure a stack trace isn't printed too many times From 726ba6630d28a63e197e9eef1cc20abd157b2910 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Mar 2016 14:36:49 -0400 Subject: [PATCH 43/45] Rebase over my PR --- src/librustc_trans/back/symbol_names.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 13a82c0baaa26..5d578011da82b 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -190,10 +190,10 @@ fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: &Instance<'tcx>, suffix: Option<&str>) -> String { - let &Instance { def: mut def_id, params: parameters } = instance; + let &Instance { def: mut def_id, ref substs } = instance; - debug!("exported_name_with_opt_suffix(def_id={:?}, parameters={:?}, suffix={:?})", - def_id, parameters, suffix); + debug!("exported_name_with_opt_suffix(def_id={:?}, substs={:?}, suffix={:?})", + def_id, substs, suffix); if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) { @@ -234,7 +234,7 @@ fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // and should not matter anyhow. let instance_ty = ccx.tcx().erase_regions(&instance_ty.ty); - let hash = get_symbol_hash(ccx, &def_path, instance_ty, parameters.as_slice()); + let hash = get_symbol_hash(ccx, &def_path, instance_ty, substs.types.as_slice()); let mut buffer = SymbolPathBuffer { names: Vec::with_capacity(def_path.data.len()) From 874574d5487d5efdf7401c3e9f318921d6dfd369 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Mar 2016 17:33:17 -0400 Subject: [PATCH 44/45] change test to be specific for msvc --- src/test/run-pass/backtrace.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 75f057e1e1d8f..36cac8f50a87c 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -60,8 +60,7 @@ fn expected(fn_name: &str) -> String { // name with namespace info, so we just see `foo` and not // `backtrace::foo` as we see on linux (which uses the linkage // name). - - if cfg!(windows) { + if cfg!(windows) && cfg!(target_env = "msvc") { format!(" - {}", fn_name) } else { format!(" - backtrace::{}", fn_name) From 1ea93c2a6388b7dcddf1ae89105a9f6f2e1da9f1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Mar 2016 19:33:13 -0400 Subject: [PATCH 45/45] remove link-guard test --- 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 --------------- 4 files changed, 60 deletions(-) delete mode 100644 src/test/run-make/link-guard/Makefile delete mode 100644 src/test/run-make/link-guard/bad/lib.rs delete mode 100644 src/test/run-make/link-guard/good/lib.rs delete mode 100644 src/test/run-make/link-guard/main.rs diff --git a/src/test/run-make/link-guard/Makefile b/src/test/run-make/link-guard/Makefile deleted file mode 100644 index 38970652cb580..0000000000000 --- a/src/test/run-make/link-guard/Makefile +++ /dev/null @@ -1,13 +0,0 @@ --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 deleted file mode 100644 index c13c0d5e92f91..0000000000000 --- a/src/test/run-make/link-guard/bad/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -// 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 deleted file mode 100644 index c13c0d5e92f91..0000000000000 --- a/src/test/run-make/link-guard/good/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -// 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 deleted file mode 100644 index c422316d9183d..0000000000000 --- a/src/test/run-make/link-guard/main.rs +++ /dev/null @@ -1,15 +0,0 @@ -// 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(); -}