Skip to content

Commit 731c0ce

Browse files
committed
Auto merge of #29961 - alexcrichton:order-dependent, r=brson
This commit fixes a bug where a crate could fail to compile depending on the order of `extern crate` directives at the top of the crate. Specifically, if the same crate is found at two locations, then if it's loaded first via `--extern` it will not emit a duplicate warning, but if it's first loaded transitively via a dep and *then* via `--extern` an error will be emitted. The loader was tweaked to catch this scenario and coalesce the loading of these two crates to prevent errors from being emitted.
2 parents 20cbba7 + 24311d0 commit 731c0ce

File tree

6 files changed

+81
-5
lines changed

6 files changed

+81
-5
lines changed

src/librustc/metadata/creader.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,12 @@ impl<'a> CrateReader<'a> {
368368
explicitly_linked: bool)
369369
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
370370
cstore::CrateSource) {
371-
match self.existing_match(name, hash, kind) {
371+
enum LookupResult {
372+
Previous(ast::CrateNum),
373+
Loaded(loader::Library),
374+
}
375+
let result = match self.existing_match(name, hash, kind) {
376+
Some(cnum) => LookupResult::Previous(cnum),
372377
None => {
373378
let mut load_ctxt = loader::Context {
374379
sess: self.sess,
@@ -386,16 +391,36 @@ impl<'a> CrateReader<'a> {
386391
should_match_name: true,
387392
};
388393
let library = load_ctxt.load_library_crate();
389-
self.register_crate(root, ident, name, span, library,
390-
explicitly_linked)
394+
395+
// In the case that we're loading a crate, but not matching
396+
// against a hash, we could load a crate which has the same hash
397+
// as an already loaded crate. If this is the case prevent
398+
// duplicates by just using the first crate.
399+
let meta_hash = decoder::get_crate_hash(library.metadata
400+
.as_slice());
401+
let mut result = LookupResult::Loaded(library);
402+
self.sess.cstore.iter_crate_data(|cnum, data| {
403+
if data.name() == name && meta_hash == data.hash() {
404+
assert!(hash.is_none());
405+
result = LookupResult::Previous(cnum);
406+
}
407+
});
408+
result
391409
}
392-
Some(cnum) => {
410+
};
411+
412+
match result {
413+
LookupResult::Previous(cnum) => {
393414
let data = self.sess.cstore.get_crate_data(cnum);
394415
if explicitly_linked && !data.explicitly_linked.get() {
395416
data.explicitly_linked.set(explicitly_linked);
396417
}
397418
(cnum, data, self.sess.cstore.get_used_crate_source(cnum).unwrap())
398419
}
420+
LookupResult::Loaded(library) => {
421+
self.register_crate(root, ident, name, span, library,
422+
explicitly_linked)
423+
}
399424
}
400425
}
401426

src/librustc/metadata/loader.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,12 @@ impl<'a> Context<'a> {
547547
continue
548548
}
549549
};
550-
if ret.is_some() {
550+
// If we've already found a candidate and we're not matching hashes,
551+
// emit an error about duplicate candidates found. If we're matching
552+
// based on a hash, however, then if we've gotten this far both
553+
// candidates have the same hash, so they're not actually
554+
// duplicates that we should warn about.
555+
if ret.is_some() && self.hash.is_none() {
551556
span_err!(self.sess, self.span, E0465,
552557
"multiple {} candidates for `{}` found",
553558
flavor, self.crate_name);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTC) foo1.rs
5+
$(RUSTC) foo2.rs
6+
mkdir $(TMPDIR)/foo
7+
cp $(TMPDIR)/libfoo1.rlib $(TMPDIR)/foo/libfoo1.rlib
8+
$(RUSTC) bar.rs --extern foo1=$(TMPDIR)/libfoo1.rlib -L $(TMPDIR)/foo
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2015 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+
extern crate foo2; // foo2 first to exhibit the bug
12+
extern crate foo1;
13+
14+
fn main() {
15+
/* ... */
16+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2015 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_type = "rlib"]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2015 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_type = "rlib"]

0 commit comments

Comments
 (0)