Skip to content

rustc: Fix extern crate being order dependent #29961

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 1 commit into from
Nov 20, 2015
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
33 changes: 29 additions & 4 deletions src/librustc/metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/librustc/metadata/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions src/test/run-make/extern-multiple-copies/Makefile
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions src/test/run-make/extern-multiple-copies/bar.rs
Original file line number Diff line number Diff line change
@@ -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() {
/* ... */
}
11 changes: 11 additions & 0 deletions src/test/run-make/extern-multiple-copies/foo1.rs
Original file line number Diff line number Diff line change
@@ -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"]
11 changes: 11 additions & 0 deletions src/test/run-make/extern-multiple-copies/foo2.rs
Original file line number Diff line number Diff line change
@@ -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"]