diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 9c2aa584aabce..6ce5d1117a63f 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -368,7 +368,12 @@ impl<'a> CrateReader<'a> { explicitly_linked: bool) -> (ast::CrateNum, Rc, 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) + } } } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index d8dead333781f..ca1562683efe7 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -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); diff --git a/src/test/run-make/extern-multiple-copies/Makefile b/src/test/run-make/extern-multiple-copies/Makefile new file mode 100644 index 0000000000000..1631aa806af09 --- /dev/null +++ b/src/test/run-make/extern-multiple-copies/Makefile @@ -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 diff --git a/src/test/run-make/extern-multiple-copies/bar.rs b/src/test/run-make/extern-multiple-copies/bar.rs new file mode 100644 index 0000000000000..a50f5de384c02 --- /dev/null +++ b/src/test/run-make/extern-multiple-copies/bar.rs @@ -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 or the MIT license +// , 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() { + /* ... */ +} diff --git a/src/test/run-make/extern-multiple-copies/foo1.rs b/src/test/run-make/extern-multiple-copies/foo1.rs new file mode 100644 index 0000000000000..0be200ddcd27d --- /dev/null +++ b/src/test/run-make/extern-multiple-copies/foo1.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] diff --git a/src/test/run-make/extern-multiple-copies/foo2.rs b/src/test/run-make/extern-multiple-copies/foo2.rs new file mode 100644 index 0000000000000..0be200ddcd27d --- /dev/null +++ b/src/test/run-make/extern-multiple-copies/foo2.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"]