about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2014-04-03 17:43:57 +0200
committerFelix S. Klock II <pnkfelix@pnkfx.org>2014-04-03 17:46:22 +0200
commit3ccbffac40958159c571ee515b85146397c0a35f (patch)
treea08badc7e48e08b130fcb5877b0c120b8edd7c61
parent7bda3df6ff894e9b522ede02b15b6772c99e7362 (diff)
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<CratePaths>`, 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.
-rw-r--r--src/librustc/metadata/creader.rs44
-rw-r--r--src/librustc/metadata/loader.rs54
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::cstore;
 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<CratePaths>,
+                     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<CratePaths>,
                       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 @@ impl<'a> 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<IdentInterner>,
-    pub rejected_via_hash: bool,
+    /// Some if rejected
+    pub rejected_via_hash: Option<ViaHash>
 }
 
 pub struct Library {
@@ -69,6 +74,25 @@ pub struct ArchiveMetadata {
     data: &'static [u8],
 }
 
+pub struct CratePaths {
+    pub ident: ~str,
+    pub dylib: Option<Path>,
+    pub rlib: Option<Path>
+}
+
+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<CratePaths>) -> 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 @@ impl<'a> Context<'a> {
             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 @@ impl<'a> Context<'a> {
         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 @@ impl<'a> Context<'a> {
             None => true,
             Some(myhash) => {
                 if *myhash != hash {
-                    self.rejected_via_hash = true;
+                    self.rejected_via_hash =
+                        Some(ViaHash{ path: libpath.clone(), });
                     false
                 } else {
                     true