rustc: Fix extern crate being order dependent

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.
This commit is contained in:
Alex Crichton 2015-10-20 21:05:39 -07:00
parent 1902021032
commit 24311d0762
6 changed files with 81 additions and 5 deletions

View File

@ -368,7 +368,12 @@ impl<'a> CrateReader<'a> {
explicitly_linked: bool)
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
match self.existing_match(name, hash, kind) {
enum LookupResult {
Previous(ast::CrateNum),
Loaded(loader::Library),
}
let result = match self.existing_match(name, hash, kind) {
Some(cnum) => LookupResult::Previous(cnum),
None => {
let mut load_ctxt = loader::Context {
sess: self.sess,
@ -386,16 +391,36 @@ impl<'a> CrateReader<'a> {
should_match_name: true,
};
let library = load_ctxt.load_library_crate();
self.register_crate(root, ident, name, span, library,
explicitly_linked)
// In the case that we're loading a crate, but not matching
// against a hash, we could load a crate which has the same hash
// as an already loaded crate. If this is the case prevent
// duplicates by just using the first crate.
let meta_hash = decoder::get_crate_hash(library.metadata
.as_slice());
let mut result = LookupResult::Loaded(library);
self.sess.cstore.iter_crate_data(|cnum, data| {
if data.name() == name && meta_hash == data.hash() {
assert!(hash.is_none());
result = LookupResult::Previous(cnum);
}
});
result
}
Some(cnum) => {
};
match result {
LookupResult::Previous(cnum) => {
let data = self.sess.cstore.get_crate_data(cnum);
if explicitly_linked && !data.explicitly_linked.get() {
data.explicitly_linked.set(explicitly_linked);
}
(cnum, data, self.sess.cstore.get_used_crate_source(cnum).unwrap())
}
LookupResult::Loaded(library) => {
self.register_crate(root, ident, name, span, library,
explicitly_linked)
}
}
}

View File

@ -547,7 +547,12 @@ impl<'a> Context<'a> {
continue
}
};
if ret.is_some() {
// If we've already found a candidate and we're not matching hashes,
// emit an error about duplicate candidates found. If we're matching
// based on a hash, however, then if we've gotten this far both
// candidates have the same hash, so they're not actually
// duplicates that we should warn about.
if ret.is_some() && self.hash.is_none() {
span_err!(self.sess, self.span, E0465,
"multiple {} candidates for `{}` found",
flavor, self.crate_name);

View File

@ -0,0 +1,8 @@
-include ../tools.mk
all:
$(RUSTC) foo1.rs
$(RUSTC) foo2.rs
mkdir $(TMPDIR)/foo
cp $(TMPDIR)/libfoo1.rlib $(TMPDIR)/foo/libfoo1.rlib
$(RUSTC) bar.rs --extern foo1=$(TMPDIR)/libfoo1.rlib -L $(TMPDIR)/foo

View File

@ -0,0 +1,16 @@
// Copyright 2015 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.
extern crate foo2; // foo2 first to exhibit the bug
extern crate foo1;
fn main() {
/* ... */
}

View File

@ -0,0 +1,11 @@
// Copyright 2015 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_type = "rlib"]

View File

@ -0,0 +1,11 @@
// Copyright 2015 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_type = "rlib"]