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.
This commit is contained in:
Felix S. Klock II 2014-04-03 17:43:57 +02:00
parent 7bda3df6ff
commit 3ccbffac40
2 changed files with 70 additions and 28 deletions

View File

@ -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 {

View File

@ -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