Skip to content

After a hash mismatch error, emit file-system paths of crates involved. #13284

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 5, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/librustc/driver/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ impl Session {
pub fn span_end_note(&self, sp: Span, msg: &str) {
self.diagnostic().span_end_note(sp, msg)
}
pub fn fileline_note(&self, sp: Span, msg: &str) {
self.diagnostic().fileline_note(sp, msg)
}
pub fn note(&self, msg: &str) {
self.diagnostic().handler().note(msg)
}
Expand Down
44 changes: 26 additions & 18 deletions src/librustc/metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand All @@ -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: vec!(),
};
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());
Expand All @@ -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);

Expand All @@ -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");
Expand All @@ -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),
Expand Down Expand Up @@ -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 {
Expand Down
58 changes: 48 additions & 10 deletions src/librustc/metadata/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ pub enum Os {
OsFreebsd
}

pub struct HashMismatch {
path: Path,
}

pub struct Context<'a> {
pub sess: &'a Session,
pub span: Span,
Expand All @@ -54,7 +58,7 @@ pub struct Context<'a> {
pub hash: Option<&'a Svh>,
pub os: Os,
pub intr: Rc<IdentInterner>,
pub rejected_via_hash: bool,
pub rejected_via_hash: Vec<HashMismatch>
}

pub struct Library {
Expand All @@ -69,6 +73,23 @@ pub struct ArchiveMetadata {
data: &'static [u8],
}

pub struct CratePaths {
pub ident: ~str,
pub dylib: Option<Path>,
pub rlib: Option<Path>
}

impl CratePaths {
fn paths(&self) -> Vec<Path> {
match (&self.dylib, &self.rlib) {
(&None, &None) => vec!(),
(&Some(ref p), &None) |
(&None, &Some(ref p)) => vec!(p.clone()),
(&Some(ref p1), &Some(ref p2)) => vec!(p1.clone(), p2.clone()),
}
}
}

// FIXME(#11857) this should be a "real" realpath
fn realpath(p: &Path) -> Path {
use std::os;
Expand All @@ -82,26 +103,43 @@ 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.len() > 0 {
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.len() > 0 {
self.sess.span_note(self.span, "perhaps this crate needs \
to be recompiled?");
let mismatches = self.rejected_via_hash.iter();
for (i, &HashMismatch{ ref path }) in mismatches.enumerate() {
self.sess.fileline_note(self.span,
format!("crate `{}` path \\#{}: {}",
self.ident, i+1, path.display()));
}
match root {
&None => {}
&Some(ref r) => {
for (i, path) in r.paths().iter().enumerate() {
self.sess.fileline_note(self.span,
format!("crate `{}` path \\#{}: {}",
r.ident, i+1, path.display()));
}
}
}
}
self.sess.abort_if_errors();
unreachable!()
Expand Down Expand Up @@ -291,7 +329,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");
Expand Down Expand Up @@ -326,7 +364,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
Expand All @@ -338,7 +376,7 @@ impl<'a> Context<'a> {
None => true,
Some(myhash) => {
if *myhash != hash {
self.rejected_via_hash = true;
self.rejected_via_hash.push(HashMismatch{ path: libpath.clone() });
false
} else {
true
Expand Down
50 changes: 42 additions & 8 deletions src/libsyntax/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,37 @@ use term;
// maximum number of lines we will print for each error; arbitrary.
static MAX_LINES: uint = 6u;

#[deriving(Clone)]
pub enum RenderSpan {
/// A FullSpan renders with both with an initial line for the
/// message, prefixed by file:linenum, followed by a summary of
/// the source code covered by the span.
FullSpan(Span),

/// A FileLine renders with just a line for the message prefixed
/// by file:linenum.
FileLine(Span),
}

impl RenderSpan {
fn span(self) -> Span {
match self {
FullSpan(s) | FileLine(s) => s
}
}
fn is_full_span(&self) -> bool {
match self {
&FullSpan(..) => true,
&FileLine(..) => false,
}
}
}

pub trait Emitter {
fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str, lvl: Level);
fn custom_emit(&mut self, cm: &codemap::CodeMap,
sp: Span, msg: &str, lvl: Level);
sp: RenderSpan, msg: &str, lvl: Level);
}

/// This structure is used to signify that a task has failed with a fatal error
Expand Down Expand Up @@ -60,7 +86,10 @@ impl SpanHandler {
self.handler.emit(Some((&self.cm, sp)), msg, Note);
}
pub fn span_end_note(&self, sp: Span, msg: &str) {
self.handler.custom_emit(&self.cm, sp, msg, Note);
self.handler.custom_emit(&self.cm, FullSpan(sp), msg, Note);
}
pub fn fileline_note(&self, sp: Span, msg: &str) {
self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note);
}
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
self.handler.emit(Some((&self.cm, sp)), msg, Bug);
Expand Down Expand Up @@ -132,7 +161,7 @@ impl Handler {
self.emit.borrow_mut().emit(cmsp, msg, lvl);
}
pub fn custom_emit(&self, cm: &codemap::CodeMap,
sp: Span, msg: &str, lvl: Level) {
sp: RenderSpan, msg: &str, lvl: Level) {
self.emit.borrow_mut().custom_emit(cm, sp, msg, lvl);
}
}
Expand Down Expand Up @@ -258,7 +287,7 @@ impl Emitter for EmitterWriter {
msg: &str,
lvl: Level) {
let error = match cmsp {
Some((cm, sp)) => emit(self, cm, sp, msg, lvl, false),
Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, lvl, false),
None => print_diagnostic(self, "", lvl, msg),
};

Expand All @@ -269,16 +298,17 @@ impl Emitter for EmitterWriter {
}

fn custom_emit(&mut self, cm: &codemap::CodeMap,
sp: Span, msg: &str, lvl: Level) {
sp: RenderSpan, msg: &str, lvl: Level) {
match emit(self, cm, sp, msg, lvl, true) {
Ok(()) => {}
Err(e) => fail!("failed to print diagnostics: {}", e),
}
}
}

fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span,
fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> {
let sp = rsp.span();
let ss = cm.span_to_str(sp);
let lines = cm.span_to_lines(sp);
if custom {
Expand All @@ -288,10 +318,14 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span,
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
let ses = cm.span_to_str(span_end);
try!(print_diagnostic(dst, ses, lvl, msg));
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
if rsp.is_full_span() {
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
}
} else {
try!(print_diagnostic(dst, ss, lvl, msg));
try!(highlight_lines(dst, cm, sp, lvl, lines));
if rsp.is_full_span() {
try!(highlight_lines(dst, cm, sp, lvl, lines));
}
}
print_macro_backtrace(dst, cm, sp)
}
Expand Down
34 changes: 34 additions & 0 deletions src/test/run-make/many-crates-but-no-match/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-include ../tools.mk

# Modelled after compile-fail/changing-crates test, but this one puts
# more than one (mismatching) candidate crate into the search path,
# which did not appear directly expressible in compile-fail/aux-build
# infrastructure.
#
# Note that we move the built libraries into target direcrtories rather than
# use the `--out-dir` option because the `../tools.mk` file already bakes a
# use of `--out-dir` into the definition of $(RUSTC).

A1=$(TMPDIR)/a1
A2=$(TMPDIR)/a2
A3=$(TMPDIR)/a3

# A hack to match distinct lines of output from a single run.
LOG=$(TMPDIR)/log.txt

all:
mkdir -p $(A1) $(A2) $(A3)
$(RUSTC) --crate-type=rlib crateA1.rs
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A1)
$(RUSTC) --crate-type=rlib -L$(A1) crateB.rs
$(RUSTC) --crate-type=rlib crateA2.rs
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A2)
$(RUSTC) --crate-type=rlib crateA3.rs
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A3)
# 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: crate \`crateA\` path #1:" $(LOG)
grep "note: crate \`crateA\` path #2:" $(LOG)
grep "note: crate \`crateB\` path #1:" $(LOG)
14 changes: 14 additions & 0 deletions src/test/run-make/many-crates-but-no-match/crateA1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_id="crateA"]

// Base crate
pub fn func<T>() {}
Loading