diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index 70d0a4e315c37..4e16fae187070 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -118,8 +118,6 @@ impl DepGraphThreadData { /// the buffer is full, this may swap.) #[inline] pub fn enqueue(&self, message: DepMessage) { - debug!("enqueue: {:?} tasks_pushed={}", message, self.tasks_pushed.get()); - // Regardless of whether dep graph construction is enabled, we // still want to check that we always have a valid task on the // stack when a read/write/etc event occurs. diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index b3918f1e4bc8b..9123463149936 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -15,6 +15,7 @@ use std::marker::PhantomData; use std::ops::{Index, IndexMut, Range}; use std::fmt; use std::vec; +use std::u32; use rustc_serialize as serialize; @@ -31,6 +32,11 @@ impl Idx for usize { fn index(self) -> usize { self } } +impl Idx for u32 { + fn new(idx: usize) -> Self { assert!(idx <= u32::MAX as usize); idx as u32 } + fn index(self) -> usize { self as usize } +} + #[derive(Clone)] pub struct IndexVec { pub raw: Vec, diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 11896e176301b..2d3302c2eef3a 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -16,6 +16,7 @@ rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } serialize = { path = "../libserialize" } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 7ef00b971c57b..2e8c5a7c23418 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -60,7 +60,7 @@ use rustc_serialize::{Encodable, EncoderHelpers}; struct DecodeContext<'a, 'b, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &'b cstore::crate_metadata, + cdata: &'b cstore::CrateMetadata, from_id_range: IdRange, to_id_range: IdRange, // Cache the last used filemap for translating spans as an optimization. @@ -121,7 +121,7 @@ impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> { /// Decodes an item from its AST in the cdata's metadata and adds it to the /// ast-map. -pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::crate_metadata, +pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, tcx: TyCtxt<'a, 'tcx, 'tcx>, parent_def_path: ast_map::DefPath, parent_did: DefId, @@ -246,7 +246,7 @@ impl def_id_encoder_helpers for S trait def_id_decoder_helpers { fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId; fn read_def_id_nodcx(&mut self, - cdata: &cstore::crate_metadata) -> DefId; + cdata: &cstore::CrateMetadata) -> DefId; } impl def_id_decoder_helpers for D @@ -258,7 +258,7 @@ impl def_id_decoder_helpers for D } fn read_def_id_nodcx(&mut self, - cdata: &cstore::crate_metadata) + cdata: &cstore::CrateMetadata) -> DefId { let did: DefId = Decodable::decode(self).unwrap(); decoder::translate_def_id(cdata, did) @@ -858,17 +858,17 @@ trait rbml_decoder_decoder_helpers<'tcx> { // Versions of the type reading functions that don't need the full // DecodeContext. fn read_ty_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) -> Ty<'tcx>; + cdata: &cstore::CrateMetadata) -> Ty<'tcx>; fn read_tys_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) -> Vec>; + cdata: &cstore::CrateMetadata) -> Vec>; fn read_substs_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) + cdata: &cstore::CrateMetadata) -> subst::Substs<'tcx>; } impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_ty_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) + cdata: &cstore::CrateMetadata) -> Ty<'tcx> { self.read_opaque(|_, doc| { Ok( @@ -879,7 +879,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_tys_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) -> Vec> { + cdata: &cstore::CrateMetadata) -> Vec> { self.read_to_vec(|this| Ok(this.read_ty_nodcx(tcx, cdata)) ) .unwrap() .into_iter() @@ -887,7 +887,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_substs_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::crate_metadata) + cdata: &cstore::CrateMetadata) -> subst::Substs<'tcx> { self.read_opaque(|_, doc| { diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 74f97de265898..ff072cce5db96 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -252,3 +252,7 @@ pub fn rustc_version() -> String { } pub const tag_panic_strategy: usize = 0x114; + +// NB: increment this if you change the format of metadata such that +// rustc_version can't be found. +pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 2ccac91ae9105..269e284b22d6c 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -12,7 +12,6 @@ //! Validates all used crates and extern libraries and loads their metadata -use common::rustc_version; use cstore::{self, CStore, CrateSource, MetadataBlob}; use decoder; use loader::{self, CratePaths}; @@ -24,7 +23,7 @@ use rustc::session::{config, Session}; use rustc::session::config::PanicStrategy; use rustc::session::search_paths::PathKind; use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; -use rustc::util::nodemap::FnvHashMap; +use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; use rustc::hir::map as hir_map; use std::cell::{RefCell, Cell}; @@ -132,7 +131,7 @@ struct ExtensionCrate { } enum PMDSource { - Registered(Rc), + Registered(Rc), Owned(MetadataBlob), } @@ -236,25 +235,6 @@ impl<'a> CrateReader<'a> { return ret; } - fn verify_rustc_version(&self, - name: &str, - span: Span, - metadata: &MetadataBlob) { - let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice()); - if crate_rustc_version != Some(rustc_version()) { - let mut err = struct_span_fatal!(self.sess, span, E0514, - "the crate `{}` has been compiled with {}, which is \ - incompatible with this version of rustc", - name, - crate_rustc_version - .as_ref().map(|s| &**s) - .unwrap_or("an old version of rustc")); - err.help("consider removing the compiled binaries and recompiling \ - with your current version of rustc"); - err.emit(); - } - } - fn verify_no_symbol_conflicts(&self, span: Span, metadata: &MetadataBlob) { @@ -294,9 +274,8 @@ impl<'a> CrateReader<'a> { span: Span, lib: loader::Library, explicitly_linked: bool) - -> (ast::CrateNum, Rc, + -> (ast::CrateNum, Rc, cstore::CrateSource) { - self.verify_rustc_version(name, span, &lib.metadata); self.verify_no_symbol_conflicts(span, &lib.metadata); // Claim this crate number and cache it @@ -318,10 +297,10 @@ impl<'a> CrateReader<'a> { let loader::Library { dylib, rlib, metadata } = lib; - let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span); + let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), cnum, span); let staged_api = self.is_staged_api(metadata.as_slice()); - let cmeta = Rc::new(cstore::crate_metadata { + let cmeta = Rc::new(cstore::CrateMetadata { name: name.to_string(), extern_crate: Cell::new(None), index: decoder::load_index(metadata.as_slice()), @@ -364,7 +343,7 @@ impl<'a> CrateReader<'a> { span: Span, kind: PathKind, explicitly_linked: bool) - -> (ast::CrateNum, Rc, cstore::CrateSource) { + -> (ast::CrateNum, Rc, cstore::CrateSource) { let result = match self.existing_match(name, hash, kind) { Some(cnum) => LoadResult::Previous(cnum), None => { @@ -381,6 +360,7 @@ impl<'a> CrateReader<'a> { rejected_via_hash: vec!(), rejected_via_triple: vec!(), rejected_via_kind: vec!(), + rejected_via_version: vec!(), should_match_name: true, }; match self.load(&mut load_ctxt) { @@ -438,8 +418,11 @@ impl<'a> CrateReader<'a> { fn update_extern_crate(&mut self, cnum: ast::CrateNum, - mut extern_crate: ExternCrate) + mut extern_crate: ExternCrate, + visited: &mut FnvHashSet<(ast::CrateNum, bool)>) { + if !visited.insert((cnum, extern_crate.direct)) { return } + let cmeta = self.cstore.get_crate_data(cnum); let old_extern_crate = cmeta.extern_crate.get(); @@ -458,11 +441,10 @@ impl<'a> CrateReader<'a> { } 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); + for &dep_cnum in cmeta.cnum_map.borrow().iter() { + self.update_extern_crate(dep_cnum, extern_crate, visited); } } @@ -470,12 +452,13 @@ impl<'a> CrateReader<'a> { fn resolve_crate_deps(&mut self, root: &Option, cdata: &[u8], - span : Span) - -> cstore::cnum_map { + krate: ast::CrateNum, + span: Span) + -> cstore::CrateNumMap { 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| { + let map: FnvHashMap<_, _> = 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, @@ -485,7 +468,13 @@ impl<'a> CrateReader<'a> { PathKind::Dependency, dep.explicitly_linked); (dep.cnum, local_cnum) - }).collect() + }).collect(); + + let max_cnum = map.values().cloned().max().unwrap_or(0); + + // we map 0 and all other holes in the map to our parent crate. The "additional" + // self-dependencies should be harmless. + (0..max_cnum+1).map(|cnum| map.get(&cnum).cloned().unwrap_or(krate)).collect() } fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { @@ -508,6 +497,7 @@ impl<'a> CrateReader<'a> { rejected_via_hash: vec!(), rejected_via_triple: vec!(), rejected_via_kind: vec!(), + rejected_via_version: vec!(), should_match_name: true, }; let library = self.load(&mut load_ctxt).or_else(|| { @@ -826,7 +816,7 @@ impl<'a> CrateReader<'a> { fn inject_dependency_if(&self, krate: ast::CrateNum, what: &str, - needs_dep: &Fn(&cstore::crate_metadata) -> bool) { + needs_dep: &Fn(&cstore::CrateMetadata) -> bool) { // don't perform this validation if the session has errors, as one of // those errors may indicate a circular dependency which could cause // this to stack overflow. @@ -837,7 +827,17 @@ impl<'a> CrateReader<'a> { // Before we inject any dependencies, make sure we don't inject a // circular dependency by validating that this crate doesn't // transitively depend on any crates satisfying `needs_dep`. - validate(self, krate, krate, what, needs_dep); + for dep in self.cstore.crate_dependencies_in_rpo(krate) { + let data = self.cstore.get_crate_data(dep); + if needs_dep(&data) { + self.sess.err(&format!("the crate `{}` cannot depend \ + on a crate that needs {}, but \ + it depends on `{}`", + self.cstore.get_crate_data(krate).name(), + what, + data.name())); + } + } // All crates satisfying `needs_dep` do not explicitly depend on the // crate provided for this compile, but in order for this compilation to @@ -849,32 +849,8 @@ impl<'a> CrateReader<'a> { } info!("injecting a dep from {} to {}", cnum, krate); - let mut cnum_map = data.cnum_map.borrow_mut(); - let remote_cnum = cnum_map.len() + 1; - let prev = cnum_map.insert(remote_cnum as ast::CrateNum, krate); - assert!(prev.is_none()); + data.cnum_map.borrow_mut().push(krate); }); - - fn validate(me: &CrateReader, - krate: ast::CrateNum, - root: ast::CrateNum, - what: &str, - needs_dep: &Fn(&cstore::crate_metadata) -> bool) { - let data = me.cstore.get_crate_data(krate); - if needs_dep(&data) { - let krate_name = data.name(); - let data = me.cstore.get_crate_data(root); - let root_name = data.name(); - me.sess.err(&format!("the crate `{}` cannot depend \ - on a crate that needs {}, but \ - it depends on `{}`", root_name, what, - krate_name)); - } - - for (_, &dep) in data.cnum_map.borrow().iter() { - validate(me, dep, root, what, needs_dep); - } - } } } @@ -948,7 +924,8 @@ impl<'a> LocalCrateReader<'a> { span: i.span, direct: true, path_len: len, - }); + }, + &mut FnvHashSet()); self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 3134a3844bc05..95e3c53ecb402 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -9,6 +9,7 @@ // except according to those terms. use cstore; +use common; use decoder; use encoder; use loader; @@ -588,7 +589,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn metadata_encoding_version(&self) -> &[u8] { - encoder::metadata_encoding_version + common::metadata_encoding_version } /// Returns a map from a sufficiently visible external item (i.e. an external item that is diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index e89f428c96f8c..774d0f7ea1886 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -15,6 +15,7 @@ pub use self::MetadataBlob::*; +use common; use creader; use decoder; use index; @@ -26,6 +27,7 @@ use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; use rustc::middle::cstore::{ExternCrate}; use rustc::session::config::PanicStrategy; +use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; use std::cell::{RefCell, Ref, Cell}; @@ -46,7 +48,7 @@ pub use middle::cstore::{CrateSource, LinkMeta}; // local crate numbers (as generated during this session). Each external // crate may refer to types in other external crates, and each has their // own crate numbers. -pub type cnum_map = FnvHashMap; +pub type CrateNumMap = IndexVec; pub enum MetadataBlob { MetadataVec(Bytes), @@ -64,7 +66,7 @@ pub struct ImportedFileMap { pub translated_filemap: Rc } -pub struct crate_metadata { +pub struct CrateMetadata { pub name: String, /// Information about the extern crate that caused this crate to @@ -73,7 +75,7 @@ pub struct crate_metadata { pub extern_crate: Cell>, pub data: MetadataBlob, - pub cnum_map: RefCell, + pub cnum_map: RefCell, pub cnum: ast::CrateNum, pub codemap_import_info: RefCell>, pub staged_api: bool, @@ -97,7 +99,7 @@ pub struct crate_metadata { pub struct CStore { pub dep_graph: DepGraph, - metas: RefCell>>, + metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell>, used_crate_sources: RefCell>, @@ -128,7 +130,7 @@ impl CStore { self.metas.borrow().len() as ast::CrateNum + 1 } - pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc { + pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc { self.metas.borrow().get(&cnum).unwrap().clone() } @@ -137,12 +139,12 @@ impl CStore { decoder::get_crate_hash(cdata.data()) } - pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc) { + pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc) { self.metas.borrow_mut().insert(cnum, data); } pub fn iter_crate_data(&self, mut i: I) where - I: FnMut(ast::CrateNum, &Rc), + I: FnMut(ast::CrateNum, &Rc), { for (&k, v) in self.metas.borrow().iter() { i(k, v); @@ -151,7 +153,7 @@ impl CStore { /// Like `iter_crate_data`, but passes source paths (if available) as well. pub fn iter_crate_data_origins(&self, mut i: I) where - I: FnMut(ast::CrateNum, &crate_metadata, Option), + I: FnMut(ast::CrateNum, &CrateMetadata, Option), { for (&k, v) in self.metas.borrow().iter() { let origin = self.opt_used_crate_source(k); @@ -182,6 +184,30 @@ impl CStore { self.statically_included_foreign_items.borrow_mut().clear(); } + pub fn crate_dependencies_in_rpo(&self, krate: ast::CrateNum) -> Vec + { + let mut ordering = Vec::new(); + self.push_dependencies_in_postorder(&mut ordering, krate); + ordering.reverse(); + ordering + } + + pub fn push_dependencies_in_postorder(&self, + ordering: &mut Vec, + krate: ast::CrateNum) + { + if ordering.contains(&krate) { return } + + let data = self.get_crate_data(krate); + for &dep in data.cnum_map.borrow().iter() { + if dep != krate { + self.push_dependencies_in_postorder(ordering, dep); + } + } + + ordering.push(krate); + } + // This method is used when generating the command line to pass through to // system linker. The linker expects undefined symbols on the left of the // command line to be defined in libraries on the right, not the other way @@ -194,17 +220,8 @@ impl CStore { pub fn do_get_used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)> { let mut ordering = Vec::new(); - fn visit(cstore: &CStore, cnum: ast::CrateNum, - ordering: &mut Vec) { - if ordering.contains(&cnum) { return } - let meta = cstore.get_crate_data(cnum); - for (_, &dep) in meta.cnum_map.borrow().iter() { - visit(cstore, dep, ordering); - } - ordering.push(cnum); - } for (&num, _) in self.metas.borrow().iter() { - visit(self, num, &mut ordering); + self.push_dependencies_in_postorder(&mut ordering, num); } info!("topological ordering: {:?}", ordering); ordering.reverse(); @@ -264,7 +281,7 @@ impl CStore { } } -impl crate_metadata { +impl CrateMetadata { pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } pub fn name(&self) -> &str { decoder::get_crate_name(self.data()) } pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) } @@ -312,20 +329,25 @@ impl crate_metadata { } impl MetadataBlob { - pub fn as_slice<'a>(&'a self) -> &'a [u8] { - let slice = match *self { + pub fn as_slice_raw<'a>(&'a self) -> &'a [u8] { + match *self { MetadataVec(ref vec) => &vec[..], MetadataArchive(ref ar) => ar.as_slice(), - }; - if slice.len() < 4 { + } + } + + pub fn as_slice<'a>(&'a self) -> &'a [u8] { + let slice = self.as_slice_raw(); + let len_offset = 4 + common::metadata_encoding_version.len(); + if slice.len() < len_offset+4 { &[] // corrupt metadata } else { - let len = (((slice[0] as u32) << 24) | - ((slice[1] as u32) << 16) | - ((slice[2] as u32) << 8) | - ((slice[3] as u32) << 0)) as usize; - if len + 4 <= slice.len() { - &slice[4.. len + 4] + let len = (((slice[len_offset+0] as u32) << 24) | + ((slice[len_offset+1] as u32) << 16) | + ((slice[len_offset+2] as u32) << 8) | + ((slice[len_offset+3] as u32) << 0)) as usize; + if len <= slice.len() - 4 - len_offset { + &slice[len_offset + 4..len_offset + len + 4] } else { &[] // corrupt or old metadata } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3efdf36acd973..0a59c152ca379 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -15,7 +15,7 @@ use self::Family::*; use astencode::decode_inlined_item; -use cstore::{self, crate_metadata}; +use cstore::{self, CrateMetadata}; use common::*; use def_key; use encoder::def_to_u64; @@ -30,7 +30,7 @@ use rustc::util::nodemap::FnvHashMap; use rustc::hir; use rustc::session::config::PanicStrategy; -use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference}; +use middle::cstore::{FoundAst, InlinedItem, LinkagePreference}; use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls}; use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; @@ -61,9 +61,9 @@ use syntax::print::pprust; use syntax::ptr::P; use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; -pub type Cmd<'a> = &'a crate_metadata; +pub type Cmd<'a> = &'a CrateMetadata; -impl crate_metadata { +impl CrateMetadata { fn get_item(&self, item_id: DefIndex) -> Option { self.index.lookup_item(self.data(), item_id).map(|pos| { reader::doc_at(self.data(), pos as usize).unwrap().doc @@ -663,7 +663,7 @@ fn each_child_of_item_or_crate(intr: Rc, mut get_crate_data: G, mut callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc, + G: FnMut(ast::CrateNum) -> Rc, { // Iterate over all children. for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) { @@ -758,7 +758,7 @@ pub fn each_child_of_item(intr: Rc, get_crate_data: G, callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc, + G: FnMut(ast::CrateNum) -> Rc, { // Find the item. let item_doc = match cdata.get_item(id) { @@ -779,7 +779,7 @@ pub fn each_top_level_item_of_crate(intr: Rc, get_crate_data: G, callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc, + G: FnMut(ast::CrateNum) -> Rc, { let root_doc = rbml::Doc::new(cdata.data()); let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); @@ -1348,25 +1348,16 @@ pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId { return DefId { krate: cdata.cnum, index: did.index }; } - match cdata.cnum_map.borrow().get(&did.krate) { - Some(&n) => { - DefId { - krate: n, - index: did.index, - } - } - None => bug!("didn't find a crate in the cnum_map") + DefId { + krate: cdata.cnum_map.borrow()[did.krate], + index: did.index } } // Translate a DefId from the current compilation environment to a DefId // for an external crate. fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { - if did.krate == cdata.cnum { - return Some(DefId { krate: LOCAL_CRATE, index: did.index }); - } - - for (&local, &global) in cdata.cnum_map.borrow().iter() { + for (local, &global) in cdata.cnum_map.borrow().iter_enumerated() { if global == did.krate { return Some(DefId { krate: local, index: did.index }); } @@ -1545,10 +1536,7 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) let cnum = spec.split(':').nth(0).unwrap(); let link = spec.split(':').nth(1).unwrap(); let cnum: ast::CrateNum = cnum.parse().unwrap(); - let cnum = match cdata.cnum_map.borrow().get(&cnum) { - Some(&n) => n, - None => bug!("didn't find a crate in the cnum_map") - }; + let cnum = cdata.cnum_map.borrow()[cnum]; result.push((cnum, if link == "d" { LinkagePreference::RequireDynamic } else { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index c23ad6d5f078f..b6f49569958d6 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1351,6 +1351,7 @@ fn my_visit_expr(expr: &hir::Expr, rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); + encode_name(rbml_w, syntax::parse::token::intern("")); rbml_w.start_tag(tag_items_closure_ty); write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); @@ -1505,7 +1506,7 @@ fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) { fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { fn get_ordered_deps(cstore: &cstore::CStore) - -> Vec<(CrateNum, Rc)> { + -> Vec<(CrateNum, Rc)> { // Pull the cnums and name,vers,hash out of cstore let mut deps = Vec::new(); cstore.iter_crate_data(|cnum, val| { @@ -1736,7 +1737,7 @@ fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) { } fn encode_crate_dep(rbml_w: &mut Encoder, - dep: &cstore::crate_metadata) { + dep: &cstore::CrateMetadata) { rbml_w.start_tag(tag_crate_dep); rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); let hash = decoder::get_crate_hash(dep.data()); @@ -1798,10 +1799,6 @@ fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) { } } -// NB: Increment this as you change the metadata encoding version. -#[allow(non_upper_case_globals)] -pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ]; - pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec { let mut wr = Cursor::new(Vec::new()); @@ -1835,12 +1832,25 @@ pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec { // the length of the metadata to the start of the metadata. Later on this // will allow us to slice the metadata to the precise length that we just // generated regardless of trailing bytes that end up in it. - let len = v.len() as u32; - v.insert(0, (len >> 0) as u8); - v.insert(0, (len >> 8) as u8); - v.insert(0, (len >> 16) as u8); - v.insert(0, (len >> 24) as u8); - return v; + // + // We also need to store the metadata encoding version here, because + // rlibs don't have it. To get older versions of rustc to ignore + // this metadata, there are 4 zero bytes at the start, which are + // treated as a length of 0 by old compilers. + + let len = v.len(); + let mut result = vec![]; + result.push(0); + result.push(0); + result.push(0); + result.push(0); + result.extend(metadata_encoding_version.iter().cloned()); + result.push((len >> 24) as u8); + result.push((len >> 16) as u8); + result.push((len >> 8) as u8); + result.push((len >> 0) as u8); + result.extend(v); + result } fn encode_metadata_inner(rbml_w: &mut Encoder, diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 1cf7282e9e95f..cd92493e3db70 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -36,6 +36,7 @@ extern crate rustc_errors as errors; #[macro_use] extern crate rustc; +extern crate rustc_data_structures; extern crate rustc_back; extern crate rustc_llvm; extern crate rustc_const_math; diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 56393b79980f6..edfdbf2aeefa8 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -213,8 +213,8 @@ //! metadata::loader or metadata::creader for all the juicy details! use cstore::{MetadataBlob, MetadataVec, MetadataArchive}; +use common::{metadata_encoding_version, rustc_version}; use decoder; -use encoder; use rustc::hir::svh::Svh; use rustc::session::Session; @@ -260,6 +260,7 @@ pub struct Context<'a> { pub rejected_via_hash: Vec, pub rejected_via_triple: Vec, pub rejected_via_kind: Vec, + pub rejected_via_version: Vec, pub should_match_name: bool, } @@ -336,6 +337,10 @@ impl<'a> Context<'a> { struct_span_err!(self.sess, self.span, E0462, "found staticlib `{}` instead of rlib or dylib{}", self.ident, add) + } else if !self.rejected_via_version.is_empty() { + struct_span_err!(self.sess, self.span, E0514, + "found crate `{}` compiled by an incompatible version of rustc{}", + self.ident, add) } else { struct_span_err!(self.sess, self.span, E0463, "can't find crate for `{}`{}", @@ -350,7 +355,7 @@ impl<'a> Context<'a> { } } if !self.rejected_via_hash.is_empty() { - err.note("perhaps this crate needs to be recompiled?"); + err.note("perhaps that crate needs to be recompiled?"); let mismatches = self.rejected_via_hash.iter(); for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() { err.note(&format!("crate `{}` path #{}: {}", @@ -367,13 +372,22 @@ impl<'a> Context<'a> { } } if !self.rejected_via_kind.is_empty() { - err.help("please recompile this crate using --crate-type lib"); + err.help("please recompile that crate using --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { err.note(&format!("crate `{}` path #{}: {}", self.ident, i+1, path.display())); } } + if !self.rejected_via_version.is_empty() { + err.help(&format!("please recompile that crate using this compiler ({})", + rustc_version())); + let mismatches = self.rejected_via_version.iter(); + for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() { + err.note(&format!("crate `{}` path #{}: {} compiled by {:?}", + self.ident, i+1, path.display(), got)); + } + } err.emit(); self.sess.abort_if_errors(); @@ -591,6 +605,17 @@ impl<'a> Context<'a> { } fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> Option { + let crate_rustc_version = decoder::crate_rustc_version(crate_data); + if crate_rustc_version != Some(rustc_version()) { + let message = crate_rustc_version.unwrap_or(format!("an unknown compiler")); + info!("Rejecting via version: expected {} got {}", rustc_version(), message); + self.rejected_via_version.push(CrateMismatch { + path: libpath.to_path_buf(), + got: message + }); + return None; + } + if self.should_match_name { match decoder::maybe_get_crate_name(crate_data) { Some(ref name) if self.crate_name == *name => {} @@ -742,6 +767,21 @@ impl ArchiveMetadata { pub fn as_slice<'a>(&'a self) -> &'a [u8] { unsafe { &*self.data } } } +fn verify_decompressed_encoding_version(blob: &MetadataBlob, filename: &Path) + -> Result<(), String> +{ + let data = blob.as_slice_raw(); + if data.len() < 4+metadata_encoding_version.len() || + !<[u8]>::eq(&data[..4], &[0, 0, 0, 0]) || + &data[4..4+metadata_encoding_version.len()] != metadata_encoding_version + { + Err((format!("incompatible metadata version found: '{}'", + filename.display()))) + } else { + Ok(()) + } +} + // Just a small wrapper to time how long reading metadata takes. fn get_metadata_section(target: &Target, flavor: CrateFlavor, filename: &Path) -> Result { @@ -772,7 +812,10 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat return match ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)) { None => Err(format!("failed to read rlib metadata: '{}'", filename.display())), - Some(blob) => Ok(blob) + Some(blob) => { + try!(verify_decompressed_encoding_version(&blob, filename)); + Ok(blob) + } }; } unsafe { @@ -801,12 +844,12 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat let cbuf = llvm::LLVMGetSectionContents(si.llsi); let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; let cvbuf: *const u8 = cbuf as *const u8; - let vlen = encoder::metadata_encoding_version.len(); + let vlen = metadata_encoding_version.len(); debug!("checking {} bytes of metadata-version stamp", vlen); let minsz = cmp::min(vlen, csz); let buf0 = slice::from_raw_parts(cvbuf, minsz); - let version_ok = buf0 == encoder::metadata_encoding_version; + let version_ok = buf0 == metadata_encoding_version; if !version_ok { return Err((format!("incompatible metadata version found: '{}'", filename.display()))); @@ -817,7 +860,11 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat csz - vlen); let bytes = slice::from_raw_parts(cvbuf1, csz - vlen); match flate::inflate_bytes(bytes) { - Ok(inflated) => return Ok(MetadataVec(inflated)), + Ok(inflated) => { + let blob = MetadataVec(inflated); + try!(verify_decompressed_encoding_version(&blob, filename)); + return Ok(blob); + } Err(_) => {} } } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index fa00ea1e7801b..ab859b88a8597 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -169,8 +169,7 @@ pub struct Instance<'tcx> { impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[], - |tcx| Some(tcx.lookup_item_type(self.def).generics)) + ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[], |_| None) } } diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 9c6ed991df8a6..c9d1eb39f0a3d 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -213,6 +213,7 @@ dependencies = [ "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_llvm 0.0.0", "serialize 0.0.0", diff --git a/src/test/compile-fail/changing-crates.rs b/src/test/compile-fail/changing-crates.rs index 0b42015848822..f74855a0849b1 100644 --- a/src/test/compile-fail/changing-crates.rs +++ b/src/test/compile-fail/changing-crates.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-lit.rs b/src/test/compile-fail/svh-change-lit.rs index eb92bcf065d3f..1638caaa92337 100644 --- a/src/test/compile-fail/svh-change-lit.rs +++ b/src/test/compile-fail/svh-change-lit.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-significant-cfg.rs b/src/test/compile-fail/svh-change-significant-cfg.rs index 7c9e0d3a92c98..99523ca699f0e 100644 --- a/src/test/compile-fail/svh-change-significant-cfg.rs +++ b/src/test/compile-fail/svh-change-significant-cfg.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-trait-bound.rs b/src/test/compile-fail/svh-change-trait-bound.rs index 1e6a7232904a8..dcf4859792d28 100644 --- a/src/test/compile-fail/svh-change-trait-bound.rs +++ b/src/test/compile-fail/svh-change-trait-bound.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-type-arg.rs b/src/test/compile-fail/svh-change-type-arg.rs index 73c35ee6f82ca..7e51ca456b21a 100644 --- a/src/test/compile-fail/svh-change-type-arg.rs +++ b/src/test/compile-fail/svh-change-type-arg.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-type-ret.rs b/src/test/compile-fail/svh-change-type-ret.rs index b8908e2cbd1e5..54ca87d84c1ec 100644 --- a/src/test/compile-fail/svh-change-type-ret.rs +++ b/src/test/compile-fail/svh-change-type-ret.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-change-type-static.rs b/src/test/compile-fail/svh-change-type-static.rs index 291e441aa5e2d..ea90faaf61088 100644 --- a/src/test/compile-fail/svh-change-type-static.rs +++ b/src/test/compile-fail/svh-change-type-static.rs @@ -17,7 +17,7 @@ extern crate a; extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on -//~| NOTE: perhaps this crate needs to be recompiled +//~| NOTE: perhaps that crate needs to be recompiled //~| NOTE: crate `a` path #1: //~| NOTE: crate `b` path #1: diff --git a/src/test/compile-fail/svh-use-trait.rs b/src/test/compile-fail/svh-use-trait.rs index ed816a93c52d2..c0a5a0a17eb26 100644 --- a/src/test/compile-fail/svh-use-trait.rs +++ b/src/test/compile-fail/svh-use-trait.rs @@ -22,7 +22,7 @@ extern crate uta; extern crate utb; //~ ERROR: found possibly newer version of crate `uta` which `utb` depends -//~| NOTE: perhaps this crate needs to be recompiled? +//~| NOTE: perhaps that crate needs to be recompiled? //~| NOTE: crate `uta` path #1: //~| NOTE: crate `utb` path #1: diff --git a/src/test/run-make/many-crates-but-no-match/Makefile b/src/test/run-make/many-crates-but-no-match/Makefile index edf8e9df465dc..0da4af34ef03d 100644 --- a/src/test/run-make/many-crates-but-no-match/Makefile +++ b/src/test/run-make/many-crates-but-no-match/Makefile @@ -28,7 +28,7 @@ all: # Ensure crateC fails to compile since A1 is "missing" and A2/A3 hashes do not match $(RUSTC) -L $(A2) -L $(A3) crateC.rs >$(LOG) 2>&1 || true grep "error: found possibly newer version of crate \`crateA\` which \`crateB\` depends on" $(LOG) - grep "note: perhaps this crate needs to be recompiled?" $(LOG) + grep "note: perhaps that crate needs to be recompiled?" $(LOG) grep "note: crate \`crateA\` path #1:" $(LOG) grep "note: crate \`crateA\` path #2:" $(LOG) grep "note: crate \`crateB\` path #1:" $(LOG)