Skip to content

Commit 0dc2910

Browse files
committed
Auto merge of #27458 - mitaa:local_cpath, r=nikomatsakis
This changes the current behaviour for two cases (that I know of) ```rust mod foo { extern crate bar; } // `bar::` changes to `foo::bar::` ``` ```rust extern crate bar as quux; // `bar::` changes to `quux::` ``` For example: ```rust mod foo { extern crate core; } fn assert_clone<T>() where T : Clone { } fn main() { assert_clone::<foo::core::atomic::AtomicBool>(); // error: the trait `core::clone::Clone` is not implemented for the type `core::atomic::AtomicBool` [E0277] // changes to // error: the trait `foo::core::clone::Clone` is not implemented for the type `foo::core::atomic::AtomicBool` [E0277] } ``` Notably the following test case broke: ```rust #[bench] fn bar(x: isize) { } //~^ ERROR mismatched types //~| expected `fn(&mut test::Bencher)` // changed to //~| expected `fn(&mut __test::test::Bencher)` ``` If a crate is linked multiple times the path with the least segments is stored. Partially addresses #1920. (this doesn't solve the issue raised about re-exports) r? @nikomatsakis
2 parents 6210dcd + dcf7ac6 commit 0dc2910

File tree

11 files changed

+260
-145
lines changed

11 files changed

+260
-145
lines changed

src/librustc/metadata/creader.rs

+144-123
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,22 @@ use syntax::codemap::{self, Span, mk_sp, Pos};
3434
use syntax::parse;
3535
use syntax::parse::token::InternedString;
3636
use syntax::visit;
37+
use syntax::util::small_vector::SmallVector;
38+
use ast_map;
3739
use log;
3840

41+
pub struct LocalCrateReader<'a, 'b:'a> {
42+
sess: &'a Session,
43+
creader: CrateReader<'a>,
44+
ast_map: &'a ast_map::Map<'b>,
45+
}
46+
3947
pub struct CrateReader<'a> {
4048
sess: &'a Session,
4149
next_crate_num: ast::CrateNum,
4250
}
4351

44-
impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> {
52+
impl<'a, 'b, 'v> visit::Visitor<'v> for LocalCrateReader<'a, 'b> {
4553
fn visit_item(&mut self, a: &ast::Item) {
4654
self.process_item(a);
4755
visit::walk_item(self, a);
@@ -152,31 +160,6 @@ impl<'a> CrateReader<'a> {
152160
}
153161
}
154162

155-
// Traverses an AST, reading all the information about use'd crates and
156-
// extern libraries necessary for later resolving, typechecking, linking,
157-
// etc.
158-
pub fn read_crates(&mut self, krate: &ast::Crate) {
159-
self.process_crate(krate);
160-
visit::walk_crate(self, krate);
161-
162-
if log_enabled!(log::DEBUG) {
163-
dump_crates(&self.sess.cstore);
164-
}
165-
166-
for &(ref name, kind) in &self.sess.opts.libs {
167-
register_native_lib(self.sess, None, name.clone(), kind);
168-
}
169-
}
170-
171-
fn process_crate(&self, c: &ast::Crate) {
172-
for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
173-
match a.value_str() {
174-
Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
175-
None => { /* fallthrough */ }
176-
}
177-
}
178-
}
179-
180163
fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
181164
match i.node {
182165
ast::ItemExternCrate(ref path_opt) => {
@@ -201,103 +184,6 @@ impl<'a> CrateReader<'a> {
201184
}
202185
}
203186

204-
fn process_item(&mut self, i: &ast::Item) {
205-
match i.node {
206-
ast::ItemExternCrate(_) => {
207-
if !should_link(i) {
208-
return;
209-
}
210-
211-
match self.extract_crate_info(i) {
212-
Some(info) => {
213-
let (cnum, _, _) = self.resolve_crate(&None,
214-
&info.ident,
215-
&info.name,
216-
None,
217-
i.span,
218-
PathKind::Crate);
219-
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
220-
}
221-
None => ()
222-
}
223-
}
224-
ast::ItemForeignMod(ref fm) => {
225-
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
226-
return;
227-
}
228-
229-
// First, add all of the custom link_args attributes
230-
let link_args = i.attrs.iter()
231-
.filter_map(|at| if at.name() == "link_args" {
232-
Some(at)
233-
} else {
234-
None
235-
})
236-
.collect::<Vec<&ast::Attribute>>();
237-
for m in &link_args {
238-
match m.value_str() {
239-
Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
240-
None => { /* fallthrough */ }
241-
}
242-
}
243-
244-
// Next, process all of the #[link(..)]-style arguments
245-
let link_args = i.attrs.iter()
246-
.filter_map(|at| if at.name() == "link" {
247-
Some(at)
248-
} else {
249-
None
250-
})
251-
.collect::<Vec<&ast::Attribute>>();
252-
for m in &link_args {
253-
match m.meta_item_list() {
254-
Some(items) => {
255-
let kind = items.iter().find(|k| {
256-
k.name() == "kind"
257-
}).and_then(|a| a.value_str());
258-
let kind = match kind {
259-
Some(k) => {
260-
if k == "static" {
261-
cstore::NativeStatic
262-
} else if self.sess.target.target.options.is_like_osx
263-
&& k == "framework" {
264-
cstore::NativeFramework
265-
} else if k == "framework" {
266-
cstore::NativeFramework
267-
} else if k == "dylib" {
268-
cstore::NativeUnknown
269-
} else {
270-
self.sess.span_err(m.span,
271-
&format!("unknown kind: `{}`",
272-
k));
273-
cstore::NativeUnknown
274-
}
275-
}
276-
None => cstore::NativeUnknown
277-
};
278-
let n = items.iter().find(|n| {
279-
n.name() == "name"
280-
}).and_then(|a| a.value_str());
281-
let n = match n {
282-
Some(n) => n,
283-
None => {
284-
self.sess.span_err(m.span,
285-
"#[link(...)] specified without \
286-
`name = \"foo\"`");
287-
InternedString::new("foo")
288-
}
289-
};
290-
register_native_lib(self.sess, Some(m.span),
291-
n.to_string(), kind);
292-
}
293-
None => {}
294-
}
295-
}
296-
}
297-
_ => { }
298-
}
299-
}
300-
301187
fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
302188
-> Option<ast::CrateNum> {
303189
let mut ret = None;
@@ -378,6 +264,7 @@ impl<'a> CrateReader<'a> {
378264

379265
let cmeta = Rc::new( cstore::crate_metadata {
380266
name: name.to_string(),
267+
local_path: RefCell::new(SmallVector::zero()),
381268
data: metadata,
382269
cnum_map: cnum_map,
383270
cnum: cnum,
@@ -592,6 +479,140 @@ impl<'a> CrateReader<'a> {
592479
}
593480
}
594481

482+
impl<'a, 'b> LocalCrateReader<'a, 'b> {
483+
pub fn new(sess: &'a Session, map: &'a ast_map::Map<'b>) -> LocalCrateReader<'a, 'b> {
484+
LocalCrateReader {
485+
sess: sess,
486+
creader: CrateReader::new(sess),
487+
ast_map: map,
488+
}
489+
}
490+
491+
// Traverses an AST, reading all the information about use'd crates and
492+
// extern libraries necessary for later resolving, typechecking, linking,
493+
// etc.
494+
pub fn read_crates(&mut self, krate: &ast::Crate) {
495+
self.process_crate(krate);
496+
visit::walk_crate(self, krate);
497+
498+
if log_enabled!(log::DEBUG) {
499+
dump_crates(&self.sess.cstore);
500+
}
501+
502+
for &(ref name, kind) in &self.sess.opts.libs {
503+
register_native_lib(self.sess, None, name.clone(), kind);
504+
}
505+
}
506+
507+
fn process_crate(&self, c: &ast::Crate) {
508+
for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
509+
match a.value_str() {
510+
Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
511+
None => { /* fallthrough */ }
512+
}
513+
}
514+
}
515+
516+
fn process_item(&mut self, i: &ast::Item) {
517+
match i.node {
518+
ast::ItemExternCrate(_) => {
519+
if !should_link(i) {
520+
return;
521+
}
522+
523+
match self.creader.extract_crate_info(i) {
524+
Some(info) => {
525+
let (cnum, cmeta, _) = self.creader.resolve_crate(&None,
526+
&info.ident,
527+
&info.name,
528+
None,
529+
i.span,
530+
PathKind::Crate);
531+
self.ast_map.with_path(i.id, |path|
532+
cmeta.update_local_path(path));
533+
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
534+
}
535+
None => ()
536+
}
537+
}
538+
ast::ItemForeignMod(ref fm) => {
539+
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
540+
return;
541+
}
542+
543+
// First, add all of the custom link_args attributes
544+
let link_args = i.attrs.iter()
545+
.filter_map(|at| if at.name() == "link_args" {
546+
Some(at)
547+
} else {
548+
None
549+
})
550+
.collect::<Vec<&ast::Attribute>>();
551+
for m in &link_args {
552+
match m.value_str() {
553+
Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
554+
None => { /* fallthrough */ }
555+
}
556+
}
557+
558+
// Next, process all of the #[link(..)]-style arguments
559+
let link_args = i.attrs.iter()
560+
.filter_map(|at| if at.name() == "link" {
561+
Some(at)
562+
} else {
563+
None
564+
})
565+
.collect::<Vec<&ast::Attribute>>();
566+
for m in &link_args {
567+
match m.meta_item_list() {
568+
Some(items) => {
569+
let kind = items.iter().find(|k| {
570+
k.name() == "kind"
571+
}).and_then(|a| a.value_str());
572+
let kind = match kind {
573+
Some(k) => {
574+
if k == "static" {
575+
cstore::NativeStatic
576+
} else if self.sess.target.target.options.is_like_osx
577+
&& k == "framework" {
578+
cstore::NativeFramework
579+
} else if k == "framework" {
580+
cstore::NativeFramework
581+
} else if k == "dylib" {
582+
cstore::NativeUnknown
583+
} else {
584+
self.sess.span_err(m.span,
585+
&format!("unknown kind: `{}`",
586+
k));
587+
cstore::NativeUnknown
588+
}
589+
}
590+
None => cstore::NativeUnknown
591+
};
592+
let n = items.iter().find(|n| {
593+
n.name() == "name"
594+
}).and_then(|a| a.value_str());
595+
let n = match n {
596+
Some(n) => n,
597+
None => {
598+
self.sess.span_err(m.span,
599+
"#[link(...)] specified without \
600+
`name = \"foo\"`");
601+
InternedString::new("foo")
602+
}
603+
};
604+
register_native_lib(self.sess, Some(m.span),
605+
n.to_string(), kind);
606+
}
607+
None => {}
608+
}
609+
}
610+
}
611+
_ => { }
612+
}
613+
}
614+
}
615+
595616
/// Imports the codemap from an external crate into the codemap of the crate
596617
/// currently being compiled (the "local crate").
597618
///

src/librustc/metadata/csearch.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use syntax::ast;
2424
use syntax::attr;
2525
use syntax::attr::AttrMetaMethods;
2626
use syntax::diagnostic::expect;
27-
use syntax::parse::token;
2827

2928
use std::collections::hash_map::HashMap;
3029

@@ -89,11 +88,12 @@ pub fn get_item_path(tcx: &ty::ctxt, def: ast::DefId) -> Vec<ast_map::PathElem>
8988
let cdata = cstore.get_crate_data(def.krate);
9089
let path = decoder::get_item_path(&*cdata, def.node);
9190

92-
// FIXME #1920: This path is not always correct if the crate is not linked
93-
// into the root namespace.
94-
let mut r = vec![ast_map::PathMod(token::intern(&cdata.name))];
95-
r.push_all(&path);
96-
r
91+
cdata.with_local_path(|cpath| {
92+
let mut r = Vec::with_capacity(cpath.len() + path.len());
93+
r.push_all(cpath);
94+
r.push_all(&path);
95+
r
96+
})
9797
}
9898

9999
pub enum FoundAst<'ast> {

src/librustc/metadata/cstore.rs

+28
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ use std::path::PathBuf;
2828
use flate::Bytes;
2929
use syntax::ast;
3030
use syntax::codemap;
31+
use syntax::parse::token;
3132
use syntax::parse::token::IdentInterner;
33+
use syntax::util::small_vector::SmallVector;
34+
use ast_map;
3235

3336
// A map from external crate numbers (as decoded from some crate file) to
3437
// local crate numbers (as generated during this session). Each external
@@ -54,6 +57,7 @@ pub struct ImportedFileMap {
5457

5558
pub struct crate_metadata {
5659
pub name: String,
60+
pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
5761
pub data: MetadataBlob,
5862
pub cnum_map: cnum_map,
5963
pub cnum: ast::CrateNum,
@@ -255,6 +259,30 @@ impl crate_metadata {
255259
filemaps
256260
}
257261
}
262+
pub fn with_local_path<T, F>(&self, f: F) -> T
263+
where F: Fn(&[ast_map::PathElem]) -> T {
264+
let cpath = self.local_path.borrow();
265+
if cpath.is_empty() {
266+
let name = ast_map::PathMod(token::intern(&self.name));
267+
f(&[name])
268+
} else {
269+
f(cpath.as_slice())
270+
}
271+
}
272+
pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) {
273+
let mut cpath = self.local_path.borrow_mut();
274+
let cap = cpath.len();
275+
match cap {
276+
0 => *cpath = candidate.collect(),
277+
1 => (),
278+
_ => {
279+
let candidate: SmallVector<_> = candidate.collect();
280+
if candidate.len() < cap {
281+
*cpath = candidate;
282+
}
283+
},
284+
}
285+
}
258286
}
259287

260288
impl MetadataBlob {

0 commit comments

Comments
 (0)