Skip to content

Commit 339d400

Browse files
committed
auto merge of #13284 : pnkfelix/rust/more-fs-info-on-crate-mismatch, r=alexcrichton
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.
2 parents 4cf8d8c + f4cde4e commit 339d400

File tree

10 files changed

+219
-36
lines changed

10 files changed

+219
-36
lines changed

src/librustc/driver/session.rs

+3
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ impl Session {
232232
pub fn span_end_note(&self, sp: Span, msg: &str) {
233233
self.diagnostic().span_end_note(sp, msg)
234234
}
235+
pub fn fileline_note(&self, sp: Span, msg: &str) {
236+
self.diagnostic().fileline_note(sp, msg)
237+
}
235238
pub fn note(&self, msg: &str) {
236239
self.diagnostic().handler().note(msg)
237240
}

src/librustc/metadata/creader.rs

+26-18
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use metadata::cstore;
2121
use metadata::decoder;
2222
use metadata::loader;
2323
use metadata::loader::Os;
24+
use metadata::loader::CratePaths;
2425

2526
use std::cell::RefCell;
2627
use std::rc::Rc;
@@ -141,7 +142,7 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) {
141142

142143
match extract_crate_info(e, i) {
143144
Some(info) => {
144-
let cnum = resolve_crate(e, None, info.ident, &info.crate_id, None,
145+
let cnum = resolve_crate(e, &None, info.ident, &info.crate_id, None,
145146
i.span);
146147
e.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
147148
}
@@ -278,13 +279,13 @@ fn existing_match(e: &Env, crate_id: &CrateId,
278279
None
279280
}
280281

281-
fn resolve_crate(e: &mut Env,
282-
root_ident: Option<&str>,
283-
ident: &str,
284-
crate_id: &CrateId,
285-
hash: Option<&Svh>,
286-
span: Span)
287-
-> ast::CrateNum {
282+
fn resolve_crate<'a>(e: &mut Env,
283+
root: &Option<CratePaths>,
284+
ident: &str,
285+
crate_id: &CrateId,
286+
hash: Option<&Svh>,
287+
span: Span)
288+
-> ast::CrateNum {
288289
match existing_match(e, crate_id, hash) {
289290
None => {
290291
let id_hash = link::crate_id_hash(crate_id);
@@ -297,11 +298,11 @@ fn resolve_crate(e: &mut Env,
297298
hash: hash.map(|a| &*a),
298299
os: e.os,
299300
intr: e.intr.clone(),
300-
rejected_via_hash: false,
301+
rejected_via_hash: vec!(),
301302
};
302303
let loader::Library {
303304
dylib, rlib, metadata
304-
} = load_ctxt.load_library_crate(root_ident);
305+
} = load_ctxt.load_library_crate(root);
305306

306307
let crate_id = decoder::get_crate_id(metadata.as_slice());
307308
let hash = decoder::get_crate_hash(metadata.as_slice());
@@ -316,15 +317,22 @@ fn resolve_crate(e: &mut Env,
316317
});
317318
e.next_crate_num += 1;
318319

319-
// Maintain a reference to the top most crate.
320-
let root_crate = match root_ident {
321-
Some(c) => c,
322-
None => load_ctxt.ident.clone()
320+
// Stash paths for top-most crate locally if necessary.
321+
let crate_paths = if root.is_none() {
322+
Some(CratePaths {
323+
ident: load_ctxt.ident.to_owned(),
324+
dylib: dylib.clone(),
325+
rlib: rlib.clone(),
326+
})
327+
} else {
328+
None
323329
};
330+
// Maintain a reference to the top most crate.
331+
let root = if root.is_some() { root } else { &crate_paths };
324332

325333
// Now resolve the crates referenced by this crate
326334
let cnum_map = resolve_crate_deps(e,
327-
Some(root_crate),
335+
root,
328336
metadata.as_slice(),
329337
span);
330338

@@ -349,7 +357,7 @@ fn resolve_crate(e: &mut Env,
349357

350358
// Go through the crate metadata and load any crates that it references
351359
fn resolve_crate_deps(e: &mut Env,
352-
root_ident: Option<&str>,
360+
root: &Option<CratePaths>,
353361
cdata: &[u8], span : Span)
354362
-> cstore::cnum_map {
355363
debug!("resolving deps of external crate");
@@ -360,7 +368,7 @@ fn resolve_crate_deps(e: &mut Env,
360368
for dep in r.iter() {
361369
let extrn_cnum = dep.cnum;
362370
debug!("resolving dep crate {} hash: `{}`", dep.crate_id, dep.hash);
363-
let local_cnum = resolve_crate(e, root_ident,
371+
let local_cnum = resolve_crate(e, root,
364372
dep.crate_id.name.as_slice(),
365373
&dep.crate_id,
366374
Some(&dep.hash),
@@ -393,7 +401,7 @@ impl<'a> Loader<'a> {
393401
impl<'a> CrateLoader for Loader<'a> {
394402
fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate {
395403
let info = extract_crate_info(&self.env, krate).unwrap();
396-
let cnum = resolve_crate(&mut self.env, None, info.ident,
404+
let cnum = resolve_crate(&mut self.env, &None, info.ident,
397405
&info.crate_id, None, krate.span);
398406
let library = self.env.sess.cstore.get_used_crate_source(cnum).unwrap();
399407
MacroCrate {

src/librustc/metadata/loader.rs

+48-10
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ pub enum Os {
4646
OsFreebsd
4747
}
4848

49+
pub struct HashMismatch {
50+
path: Path,
51+
}
52+
4953
pub struct Context<'a> {
5054
pub sess: &'a Session,
5155
pub span: Span,
@@ -55,7 +59,7 @@ pub struct Context<'a> {
5559
pub hash: Option<&'a Svh>,
5660
pub os: Os,
5761
pub intr: Rc<IdentInterner>,
58-
pub rejected_via_hash: bool,
62+
pub rejected_via_hash: Vec<HashMismatch>
5963
}
6064

6165
pub struct Library {
@@ -70,6 +74,23 @@ pub struct ArchiveMetadata {
7074
data: &'static [u8],
7175
}
7276

77+
pub struct CratePaths {
78+
pub ident: ~str,
79+
pub dylib: Option<Path>,
80+
pub rlib: Option<Path>
81+
}
82+
83+
impl CratePaths {
84+
fn paths(&self) -> Vec<Path> {
85+
match (&self.dylib, &self.rlib) {
86+
(&None, &None) => vec!(),
87+
(&Some(ref p), &None) |
88+
(&None, &Some(ref p)) => vec!(p.clone()),
89+
(&Some(ref p1), &Some(ref p2)) => vec!(p1.clone(), p2.clone()),
90+
}
91+
}
92+
}
93+
7394
// FIXME(#11857) this should be a "real" realpath
7495
fn realpath(p: &Path) -> Path {
7596
use std::os;
@@ -83,26 +104,43 @@ fn realpath(p: &Path) -> Path {
83104
}
84105

85106
impl<'a> Context<'a> {
86-
pub fn load_library_crate(&mut self, root_ident: Option<&str>) -> Library {
107+
pub fn load_library_crate(&mut self, root: &Option<CratePaths>) -> Library {
87108
match self.find_library_crate() {
88109
Some(t) => t,
89110
None => {
90111
self.sess.abort_if_errors();
91-
let message = if self.rejected_via_hash {
112+
let message = if self.rejected_via_hash.len() > 0 {
92113
format!("found possibly newer version of crate `{}`",
93114
self.ident)
94115
} else {
95116
format!("can't find crate for `{}`", self.ident)
96117
};
97-
let message = match root_ident {
98-
None => message,
99-
Some(c) => format!("{} which `{}` depends on", message, c),
118+
let message = match root {
119+
&None => message,
120+
&Some(ref r) => format!("{} which `{}` depends on",
121+
message, r.ident)
100122
};
101123
self.sess.span_err(self.span, message);
102124

103-
if self.rejected_via_hash {
125+
if self.rejected_via_hash.len() > 0 {
104126
self.sess.span_note(self.span, "perhaps this crate needs \
105127
to be recompiled?");
128+
let mismatches = self.rejected_via_hash.iter();
129+
for (i, &HashMismatch{ ref path }) in mismatches.enumerate() {
130+
self.sess.fileline_note(self.span,
131+
format!("crate `{}` path \\#{}: {}",
132+
self.ident, i+1, path.display()));
133+
}
134+
match root {
135+
&None => {}
136+
&Some(ref r) => {
137+
for (i, path) in r.paths().iter().enumerate() {
138+
self.sess.fileline_note(self.span,
139+
format!("crate `{}` path \\#{}: {}",
140+
r.ident, i+1, path.display()));
141+
}
142+
}
143+
}
106144
}
107145
self.sess.abort_if_errors();
108146
unreachable!()
@@ -292,7 +330,7 @@ impl<'a> Context<'a> {
292330
info!("{} reading metadata from: {}", flavor, lib.display());
293331
let metadata = match get_metadata_section(self.os, &lib) {
294332
Ok(blob) => {
295-
if self.crate_matches(blob.as_slice()) {
333+
if self.crate_matches(blob.as_slice(), &lib) {
296334
blob
297335
} else {
298336
info!("metadata mismatch");
@@ -327,7 +365,7 @@ impl<'a> Context<'a> {
327365
return if error > 0 {None} else {ret}
328366
}
329367

330-
fn crate_matches(&mut self, crate_data: &[u8]) -> bool {
368+
fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool {
331369
match decoder::maybe_get_crate_id(crate_data) {
332370
Some(ref id) if self.crate_id.matches(id) => {}
333371
_ => return false
@@ -339,7 +377,7 @@ impl<'a> Context<'a> {
339377
None => true,
340378
Some(myhash) => {
341379
if *myhash != hash {
342-
self.rejected_via_hash = true;
380+
self.rejected_via_hash.push(HashMismatch{ path: libpath.clone() });
343381
false
344382
} else {
345383
true

src/libsyntax/diagnostic.rs

+42-8
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,37 @@ use term;
2020
// maximum number of lines we will print for each error; arbitrary.
2121
static MAX_LINES: uint = 6u;
2222

23+
#[deriving(Clone)]
24+
pub enum RenderSpan {
25+
/// A FullSpan renders with both with an initial line for the
26+
/// message, prefixed by file:linenum, followed by a summary of
27+
/// the source code covered by the span.
28+
FullSpan(Span),
29+
30+
/// A FileLine renders with just a line for the message prefixed
31+
/// by file:linenum.
32+
FileLine(Span),
33+
}
34+
35+
impl RenderSpan {
36+
fn span(self) -> Span {
37+
match self {
38+
FullSpan(s) | FileLine(s) => s
39+
}
40+
}
41+
fn is_full_span(&self) -> bool {
42+
match self {
43+
&FullSpan(..) => true,
44+
&FileLine(..) => false,
45+
}
46+
}
47+
}
48+
2349
pub trait Emitter {
2450
fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
2551
msg: &str, lvl: Level);
2652
fn custom_emit(&mut self, cm: &codemap::CodeMap,
27-
sp: Span, msg: &str, lvl: Level);
53+
sp: RenderSpan, msg: &str, lvl: Level);
2854
}
2955

3056
/// This structure is used to signify that a task has failed with a fatal error
@@ -60,7 +86,10 @@ impl SpanHandler {
6086
self.handler.emit(Some((&self.cm, sp)), msg, Note);
6187
}
6288
pub fn span_end_note(&self, sp: Span, msg: &str) {
63-
self.handler.custom_emit(&self.cm, sp, msg, Note);
89+
self.handler.custom_emit(&self.cm, FullSpan(sp), msg, Note);
90+
}
91+
pub fn fileline_note(&self, sp: Span, msg: &str) {
92+
self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note);
6493
}
6594
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
6695
self.handler.emit(Some((&self.cm, sp)), msg, Bug);
@@ -132,7 +161,7 @@ impl Handler {
132161
self.emit.borrow_mut().emit(cmsp, msg, lvl);
133162
}
134163
pub fn custom_emit(&self, cm: &codemap::CodeMap,
135-
sp: Span, msg: &str, lvl: Level) {
164+
sp: RenderSpan, msg: &str, lvl: Level) {
136165
self.emit.borrow_mut().custom_emit(cm, sp, msg, lvl);
137166
}
138167
}
@@ -258,7 +287,7 @@ impl Emitter for EmitterWriter {
258287
msg: &str,
259288
lvl: Level) {
260289
let error = match cmsp {
261-
Some((cm, sp)) => emit(self, cm, sp, msg, lvl, false),
290+
Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, lvl, false),
262291
None => print_diagnostic(self, "", lvl, msg),
263292
};
264293

@@ -269,16 +298,17 @@ impl Emitter for EmitterWriter {
269298
}
270299

271300
fn custom_emit(&mut self, cm: &codemap::CodeMap,
272-
sp: Span, msg: &str, lvl: Level) {
301+
sp: RenderSpan, msg: &str, lvl: Level) {
273302
match emit(self, cm, sp, msg, lvl, true) {
274303
Ok(()) => {}
275304
Err(e) => fail!("failed to print diagnostics: {}", e),
276305
}
277306
}
278307
}
279308

280-
fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span,
309+
fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
281310
msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> {
311+
let sp = rsp.span();
282312
let ss = cm.span_to_str(sp);
283313
let lines = cm.span_to_lines(sp);
284314
if custom {
@@ -288,10 +318,14 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span,
288318
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
289319
let ses = cm.span_to_str(span_end);
290320
try!(print_diagnostic(dst, ses, lvl, msg));
291-
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
321+
if rsp.is_full_span() {
322+
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
323+
}
292324
} else {
293325
try!(print_diagnostic(dst, ss, lvl, msg));
294-
try!(highlight_lines(dst, cm, sp, lvl, lines));
326+
if rsp.is_full_span() {
327+
try!(highlight_lines(dst, cm, sp, lvl, lines));
328+
}
295329
}
296330
print_macro_backtrace(dst, cm, sp)
297331
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
-include ../tools.mk
2+
3+
# Modelled after compile-fail/changing-crates test, but this one puts
4+
# more than one (mismatching) candidate crate into the search path,
5+
# which did not appear directly expressible in compile-fail/aux-build
6+
# infrastructure.
7+
#
8+
# Note that we move the built libraries into target direcrtories rather than
9+
# use the `--out-dir` option because the `../tools.mk` file already bakes a
10+
# use of `--out-dir` into the definition of $(RUSTC).
11+
12+
A1=$(TMPDIR)/a1
13+
A2=$(TMPDIR)/a2
14+
A3=$(TMPDIR)/a3
15+
16+
# A hack to match distinct lines of output from a single run.
17+
LOG=$(TMPDIR)/log.txt
18+
19+
all:
20+
mkdir -p $(A1) $(A2) $(A3)
21+
$(RUSTC) --crate-type=rlib crateA1.rs
22+
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A1)
23+
$(RUSTC) --crate-type=rlib -L$(A1) crateB.rs
24+
$(RUSTC) --crate-type=rlib crateA2.rs
25+
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A2)
26+
$(RUSTC) --crate-type=rlib crateA3.rs
27+
mv $(TMPDIR)/$(call RLIB_GLOB,crateA) $(A3)
28+
# Ensure crateC fails to compile since A1 is "missing" and A2/A3 hashes do not match
29+
$(RUSTC) -L$(A2) -L$(A3) crateC.rs >$(LOG) 2>&1 || true
30+
grep "error: found possibly newer version of crate \`crateA\` which \`crateB\` depends on" $(LOG)
31+
grep "note: perhaps this crate needs to be recompiled?" $(LOG)
32+
grep "note: crate \`crateA\` path #1:" $(LOG)
33+
grep "note: crate \`crateA\` path #2:" $(LOG)
34+
grep "note: crate \`crateB\` path #1:" $(LOG)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_id="crateA"]
12+
13+
// Base crate
14+
pub fn func<T>() {}

0 commit comments

Comments
 (0)