Skip to content

Commit 5f295f2

Browse files
committed
rustc: Fix again order-dependence in extern crate
Originally fixed in #29961 the bug was unfortunately still present in the face of crates using `#[macro_use]`. This commit refactors for the two code paths to share common logic to ensure that they both pick up the same bug fix. Closes #33762
1 parent f4e4ec7 commit 5f295f2

File tree

5 files changed

+143
-49
lines changed

5 files changed

+143
-49
lines changed

src/librustc_metadata/creader.rs

+80-49
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ impl PMDSource {
143143
}
144144
}
145145

146+
enum LoadResult {
147+
Previous(ast::CrateNum),
148+
Loaded(loader::Library),
149+
}
150+
146151
impl<'a> CrateReader<'a> {
147152
pub fn new(sess: &'a Session,
148153
cstore: &'a CStore,
@@ -358,12 +363,8 @@ impl<'a> CrateReader<'a> {
358363
kind: PathKind,
359364
explicitly_linked: bool)
360365
-> (ast::CrateNum, Rc<cstore::crate_metadata>, cstore::CrateSource) {
361-
enum LookupResult {
362-
Previous(ast::CrateNum),
363-
Loaded(loader::Library),
364-
}
365366
let result = match self.existing_match(name, hash, kind) {
366-
Some(cnum) => LookupResult::Previous(cnum),
367+
Some(cnum) => LoadResult::Previous(cnum),
367368
None => {
368369
let mut load_ctxt = loader::Context {
369370
sess: self.sess,
@@ -380,40 +381,59 @@ impl<'a> CrateReader<'a> {
380381
rejected_via_kind: vec!(),
381382
should_match_name: true,
382383
};
383-
let library = load_ctxt.load_library_crate();
384-
385-
// In the case that we're loading a crate, but not matching
386-
// against a hash, we could load a crate which has the same hash
387-
// as an already loaded crate. If this is the case prevent
388-
// duplicates by just using the first crate.
389-
let meta_hash = decoder::get_crate_hash(library.metadata
390-
.as_slice());
391-
let mut result = LookupResult::Loaded(library);
392-
self.cstore.iter_crate_data(|cnum, data| {
393-
if data.name() == name && meta_hash == data.hash() {
394-
assert!(hash.is_none());
395-
result = LookupResult::Previous(cnum);
396-
}
397-
});
398-
result
384+
match self.load(&mut load_ctxt) {
385+
Some(result) => result,
386+
None => load_ctxt.report_load_errs(),
387+
}
399388
}
400389
};
401390

402391
match result {
403-
LookupResult::Previous(cnum) => {
392+
LoadResult::Previous(cnum) => {
404393
let data = self.cstore.get_crate_data(cnum);
405394
if explicitly_linked && !data.explicitly_linked.get() {
406395
data.explicitly_linked.set(explicitly_linked);
407396
}
408397
(cnum, data, self.cstore.used_crate_source(cnum))
409398
}
410-
LookupResult::Loaded(library) => {
399+
LoadResult::Loaded(library) => {
411400
self.register_crate(root, ident, name, span, library,
412401
explicitly_linked)
413402
}
414403
}
415404
}
416405

406+
fn load(&mut self, loader: &mut loader::Context) -> Option<LoadResult> {
407+
let library = match loader.maybe_load_library_crate() {
408+
Some(lib) => lib,
409+
None => return None,
410+
};
411+
412+
// In the case that we're loading a crate, but not matching
413+
// against a hash, we could load a crate which has the same hash
414+
// as an already loaded crate. If this is the case prevent
415+
// duplicates by just using the first crate.
416+
//
417+
// Note that we only do this for target triple crates, though, as we
418+
// don't want to match a host crate against an equivalent target one
419+
// already loaded.
420+
if loader.triple == self.sess.opts.target_triple {
421+
let meta_hash = decoder::get_crate_hash(library.metadata.as_slice());
422+
let meta_name = decoder::get_crate_name(library.metadata.as_slice())
423+
.to_string();
424+
let mut result = LoadResult::Loaded(library);
425+
self.cstore.iter_crate_data(|cnum, data| {
426+
if data.name() == meta_name && meta_hash == data.hash() {
427+
assert!(loader.hash.is_none());
428+
result = LoadResult::Previous(cnum);
429+
}
430+
});
431+
Some(result)
432+
} else {
433+
Some(LoadResult::Loaded(library))
434+
}
435+
}
436+
417437
fn update_extern_crate(&mut self,
418438
cnum: ast::CrateNum,
419439
mut extern_crate: ExternCrate)
@@ -488,35 +508,46 @@ impl<'a> CrateReader<'a> {
488508
rejected_via_kind: vec!(),
489509
should_match_name: true,
490510
};
491-
let library = match load_ctxt.maybe_load_library_crate() {
492-
Some(l) => l,
493-
None if is_cross => {
494-
// Try loading from target crates. This will abort later if we
495-
// try to load a plugin registrar function,
496-
target_only = true;
497-
should_link = info.should_link;
498-
499-
load_ctxt.target = &self.sess.target.target;
500-
load_ctxt.triple = target_triple;
501-
load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);
502-
load_ctxt.load_library_crate()
511+
let library = self.load(&mut load_ctxt).or_else(|| {
512+
if !is_cross {
513+
return None
503514
}
504-
None => { load_ctxt.report_load_errs(); },
515+
// Try loading from target crates. This will abort later if we
516+
// try to load a plugin registrar function,
517+
target_only = true;
518+
should_link = info.should_link;
519+
520+
load_ctxt.target = &self.sess.target.target;
521+
load_ctxt.triple = target_triple;
522+
load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);
523+
524+
self.load(&mut load_ctxt)
525+
});
526+
let library = match library {
527+
Some(l) => l,
528+
None => load_ctxt.report_load_errs(),
505529
};
506530

507-
let dylib = library.dylib.clone();
508-
let register = should_link && self.existing_match(&info.name,
509-
None,
510-
PathKind::Crate).is_none();
511-
let metadata = if register {
512-
// Register crate now to avoid double-reading metadata
513-
let (_, cmd, _) = self.register_crate(&None, &info.ident,
514-
&info.name, span, library,
515-
true);
516-
PMDSource::Registered(cmd)
517-
} else {
518-
// Not registering the crate; just hold on to the metadata
519-
PMDSource::Owned(library.metadata)
531+
let (dylib, metadata) = match library {
532+
LoadResult::Previous(cnum) => {
533+
let dylib = self.cstore.opt_used_crate_source(cnum).unwrap().dylib;
534+
let data = self.cstore.get_crate_data(cnum);
535+
(dylib, PMDSource::Registered(data))
536+
}
537+
LoadResult::Loaded(library) => {
538+
let dylib = library.dylib.clone();
539+
let metadata = if should_link {
540+
// Register crate now to avoid double-reading metadata
541+
let (_, cmd, _) = self.register_crate(&None, &info.ident,
542+
&info.name, span,
543+
library, true);
544+
PMDSource::Registered(cmd)
545+
} else {
546+
// Not registering the crate; just hold on to the metadata
547+
PMDSource::Owned(library.metadata)
548+
};
549+
(dylib, metadata)
550+
}
520551
};
521552

522553
ExtensionCrate {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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 \
9+
--extern foo1=$(TMPDIR)/foo/libfoo1.rlib \
10+
--extern foo2=$(TMPDIR)/libfoo2.rlib
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
#[macro_use]
12+
extern crate foo2; // foo2 first to exhibit the bug
13+
#[macro_use]
14+
extern crate foo1;
15+
16+
fn main() {
17+
foo2::foo2(foo1::A);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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"]
12+
13+
pub struct A;
14+
15+
pub fn foo1(a: A) {
16+
drop(a);
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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"]
12+
13+
#[macro_use]
14+
extern crate foo1;
15+
16+
pub fn foo2(a: foo1::A) {
17+
foo1::foo1(a);
18+
}

0 commit comments

Comments
 (0)