From 3ccbffac40958159c571ee515b85146397c0a35f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 3 Apr 2014 17:43:57 +0200 Subject: [PATCH] After a hash mismatch error, emit file-system paths of crates involved. Fix #13266. There is a little bit of acrobatics in the definition of `crate_paths` to avoid calling `clone()` on the dylib/rlib unless we actually are going to need them. The other oddity is that I have replaced the `root_ident: Option<&str>` parameter with a `root: &Option`, which may surprise one who was expecting to see something like: `root: Option<&CratePaths>`. I went with the approach here because I could not come up with code for the alternative that was acceptable to the borrow checker. --- src/librustc/metadata/creader.rs | 44 +++++++++++++++----------- src/librustc/metadata/loader.rs | 54 ++++++++++++++++++++++++++------ 2 files changed, 70 insertions(+), 28 deletions(-) diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 36febfc1a09..44f85bdb20f 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -21,6 +21,7 @@ use metadata::decoder; use metadata::loader; use metadata::loader::Os; +use metadata::loader::CratePaths; use std::cell::RefCell; use std::rc::Rc; @@ -141,7 +142,7 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) { match extract_crate_info(e, i) { Some(info) => { - let cnum = resolve_crate(e, None, info.ident, &info.crate_id, None, + let cnum = resolve_crate(e, &None, info.ident, &info.crate_id, None, i.span); e.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } @@ -278,13 +279,13 @@ fn existing_match(e: &Env, crate_id: &CrateId, None } -fn resolve_crate(e: &mut Env, - root_ident: Option<&str>, - ident: &str, - crate_id: &CrateId, - hash: Option<&Svh>, - span: Span) - -> ast::CrateNum { +fn resolve_crate<'a>(e: &mut Env, + root: &Option, + ident: &str, + crate_id: &CrateId, + hash: Option<&Svh>, + span: Span) + -> ast::CrateNum { match existing_match(e, crate_id, hash) { None => { let id_hash = link::crate_id_hash(crate_id); @@ -297,11 +298,11 @@ fn resolve_crate(e: &mut Env, hash: hash.map(|a| &*a), os: e.os, intr: e.intr.clone(), - rejected_via_hash: false, + rejected_via_hash: None, }; let loader::Library { dylib, rlib, metadata - } = load_ctxt.load_library_crate(root_ident); + } = load_ctxt.load_library_crate(root); let crate_id = decoder::get_crate_id(metadata.as_slice()); let hash = decoder::get_crate_hash(metadata.as_slice()); @@ -316,15 +317,22 @@ fn resolve_crate(e: &mut Env, }); e.next_crate_num += 1; - // Maintain a reference to the top most crate. - let root_crate = match root_ident { - Some(c) => c, - None => load_ctxt.ident.clone() + // Stash paths for top-most crate locally if necessary. + let crate_paths = if root.is_none() { + Some(CratePaths { + ident: load_ctxt.ident.to_owned(), + dylib: dylib.clone(), + rlib: rlib.clone(), + }) + } else { + None }; + // Maintain a reference to the top most crate. + let root = if root.is_some() { root } else { &crate_paths }; // Now resolve the crates referenced by this crate let cnum_map = resolve_crate_deps(e, - Some(root_crate), + root, metadata.as_slice(), span); @@ -349,7 +357,7 @@ fn resolve_crate(e: &mut Env, // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(e: &mut Env, - root_ident: Option<&str>, + root: &Option, cdata: &[u8], span : Span) -> cstore::cnum_map { debug!("resolving deps of external crate"); @@ -360,7 +368,7 @@ fn resolve_crate_deps(e: &mut Env, for dep in r.iter() { let extrn_cnum = dep.cnum; debug!("resolving dep crate {} hash: `{}`", dep.crate_id, dep.hash); - let local_cnum = resolve_crate(e, root_ident, + let local_cnum = resolve_crate(e, root, dep.crate_id.name.as_slice(), &dep.crate_id, Some(&dep.hash), @@ -393,7 +401,7 @@ pub fn new(sess: &'a Session) -> Loader<'a> { impl<'a> CrateLoader for Loader<'a> { fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate { let info = extract_crate_info(&self.env, krate).unwrap(); - let cnum = resolve_crate(&mut self.env, None, info.ident, + let cnum = resolve_crate(&mut self.env, &None, info.ident, &info.crate_id, None, krate.span); let library = self.env.sess.cstore.get_used_crate_source(cnum).unwrap(); MacroCrate { diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 8a3d6567c77..caa2c6c0133 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -45,6 +45,10 @@ pub enum Os { OsFreebsd } +pub struct ViaHash { + path: Path, +} + pub struct Context<'a> { pub sess: &'a Session, pub span: Span, @@ -54,7 +58,8 @@ pub struct Context<'a> { pub hash: Option<&'a Svh>, pub os: Os, pub intr: Rc, - pub rejected_via_hash: bool, + /// Some if rejected + pub rejected_via_hash: Option } pub struct Library { @@ -69,6 +74,25 @@ pub struct ArchiveMetadata { data: &'static [u8], } +pub struct CratePaths { + pub ident: ~str, + pub dylib: Option, + pub rlib: Option +} + +impl CratePaths { + fn describe_paths(&self) -> ~str { + match (&self.dylib, &self.rlib) { + (&None, &None) + => ~"", + (&Some(ref p), &None) | (&None, &Some(ref p)) + => format!("{}", p.display()), + (&Some(ref p1), &Some(ref p2)) + => format!("{}, {}", p1.display(), p2.display()), + } + } +} + // FIXME(#11857) this should be a "real" realpath fn realpath(p: &Path) -> Path { use std::os; @@ -82,26 +106,35 @@ fn realpath(p: &Path) -> Path { } impl<'a> Context<'a> { - pub fn load_library_crate(&mut self, root_ident: Option<&str>) -> Library { + pub fn load_library_crate(&mut self, root: &Option) -> Library { match self.find_library_crate() { Some(t) => t, None => { self.sess.abort_if_errors(); - let message = if self.rejected_via_hash { + let message = if self.rejected_via_hash.is_some() { format!("found possibly newer version of crate `{}`", self.ident) } else { format!("can't find crate for `{}`", self.ident) }; - let message = match root_ident { - None => message, - Some(c) => format!("{} which `{}` depends on", message, c), + let message = match root { + &None => message, + &Some(ref r) => format!("{} which `{}` depends on", + message, r.ident) }; self.sess.span_err(self.span, message); - if self.rejected_via_hash { + if self.rejected_via_hash.is_some() { self.sess.span_note(self.span, "perhaps this crate needs \ to be recompiled?"); + self.rejected_via_hash.as_ref().map( + |r| self.sess.note(format!( + "crate `{}` at path: {}", + self.ident, r.path.display()))); + root.as_ref().map( + |r| self.sess.note(format!( + "crate `{}` at path(s): {}", + r.ident, r.describe_paths()))); } self.sess.abort_if_errors(); unreachable!() @@ -291,7 +324,7 @@ fn extract_one(&mut self, m: HashSet, flavor: &str, info!("{} reading metadata from: {}", flavor, lib.display()); let metadata = match get_metadata_section(self.os, &lib) { Ok(blob) => { - if self.crate_matches(blob.as_slice()) { + if self.crate_matches(blob.as_slice(), &lib) { blob } else { info!("metadata mismatch"); @@ -326,7 +359,7 @@ fn extract_one(&mut self, m: HashSet, flavor: &str, return if error > 0 {None} else {ret} } - fn crate_matches(&mut self, crate_data: &[u8]) -> bool { + fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool { match decoder::maybe_get_crate_id(crate_data) { Some(ref id) if self.crate_id.matches(id) => {} _ => return false @@ -338,7 +371,8 @@ fn crate_matches(&mut self, crate_data: &[u8]) -> bool { None => true, Some(myhash) => { if *myhash != hash { - self.rejected_via_hash = true; + self.rejected_via_hash = + Some(ViaHash{ path: libpath.clone(), }); false } else { true -- GitLab