Skip to content

Commit

Permalink
Auto merge of #27458 - mitaa:local_cpath, r=nikomatsakis
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Aug 5, 2015
2 parents 6210dcd + dcf7ac6 commit 0dc2910
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 145 deletions.
267 changes: 144 additions & 123 deletions src/librustc/metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,22 @@ use syntax::codemap::{self, Span, mk_sp, Pos};
use syntax::parse;
use syntax::parse::token::InternedString;
use syntax::visit;
use syntax::util::small_vector::SmallVector;
use ast_map;
use log;

pub struct LocalCrateReader<'a, 'b:'a> {
sess: &'a Session,
creader: CrateReader<'a>,
ast_map: &'a ast_map::Map<'b>,
}

pub struct CrateReader<'a> {
sess: &'a Session,
next_crate_num: ast::CrateNum,
}

impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> {
impl<'a, 'b, 'v> visit::Visitor<'v> for LocalCrateReader<'a, 'b> {
fn visit_item(&mut self, a: &ast::Item) {
self.process_item(a);
visit::walk_item(self, a);
Expand Down Expand Up @@ -152,31 +160,6 @@ impl<'a> CrateReader<'a> {
}
}

// Traverses an AST, reading all the information about use'd crates and
// extern libraries necessary for later resolving, typechecking, linking,
// etc.
pub fn read_crates(&mut self, krate: &ast::Crate) {
self.process_crate(krate);
visit::walk_crate(self, krate);

if log_enabled!(log::DEBUG) {
dump_crates(&self.sess.cstore);
}

for &(ref name, kind) in &self.sess.opts.libs {
register_native_lib(self.sess, None, name.clone(), kind);
}
}

fn process_crate(&self, c: &ast::Crate) {
for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
match a.value_str() {
Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
None => { /* fallthrough */ }
}
}
}

fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
match i.node {
ast::ItemExternCrate(ref path_opt) => {
Expand All @@ -201,103 +184,6 @@ impl<'a> CrateReader<'a> {
}
}

fn process_item(&mut self, i: &ast::Item) {
match i.node {
ast::ItemExternCrate(_) => {
if !should_link(i) {
return;
}

match self.extract_crate_info(i) {
Some(info) => {
let (cnum, _, _) = self.resolve_crate(&None,
&info.ident,
&info.name,
None,
i.span,
PathKind::Crate);
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
}
None => ()
}
}
ast::ItemForeignMod(ref fm) => {
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
return;
}

// First, add all of the custom link_args attributes
let link_args = i.attrs.iter()
.filter_map(|at| if at.name() == "link_args" {
Some(at)
} else {
None
})
.collect::<Vec<&ast::Attribute>>();
for m in &link_args {
match m.value_str() {
Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
None => { /* fallthrough */ }
}
}

// Next, process all of the #[link(..)]-style arguments
let link_args = i.attrs.iter()
.filter_map(|at| if at.name() == "link" {
Some(at)
} else {
None
})
.collect::<Vec<&ast::Attribute>>();
for m in &link_args {
match m.meta_item_list() {
Some(items) => {
let kind = items.iter().find(|k| {
k.name() == "kind"
}).and_then(|a| a.value_str());
let kind = match kind {
Some(k) => {
if k == "static" {
cstore::NativeStatic
} else if self.sess.target.target.options.is_like_osx
&& k == "framework" {
cstore::NativeFramework
} else if k == "framework" {
cstore::NativeFramework
} else if k == "dylib" {
cstore::NativeUnknown
} else {
self.sess.span_err(m.span,
&format!("unknown kind: `{}`",
k));
cstore::NativeUnknown
}
}
None => cstore::NativeUnknown
};
let n = items.iter().find(|n| {
n.name() == "name"
}).and_then(|a| a.value_str());
let n = match n {
Some(n) => n,
None => {
self.sess.span_err(m.span,
"#[link(...)] specified without \
`name = \"foo\"`");
InternedString::new("foo")
}
};
register_native_lib(self.sess, Some(m.span),
n.to_string(), kind);
}
None => {}
}
}
}
_ => { }
}
}

fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
-> Option<ast::CrateNum> {
let mut ret = None;
Expand Down Expand Up @@ -378,6 +264,7 @@ impl<'a> CrateReader<'a> {

let cmeta = Rc::new( cstore::crate_metadata {
name: name.to_string(),
local_path: RefCell::new(SmallVector::zero()),
data: metadata,
cnum_map: cnum_map,
cnum: cnum,
Expand Down Expand Up @@ -592,6 +479,140 @@ impl<'a> CrateReader<'a> {
}
}

impl<'a, 'b> LocalCrateReader<'a, 'b> {
pub fn new(sess: &'a Session, map: &'a ast_map::Map<'b>) -> LocalCrateReader<'a, 'b> {
LocalCrateReader {
sess: sess,
creader: CrateReader::new(sess),
ast_map: map,
}
}

// Traverses an AST, reading all the information about use'd crates and
// extern libraries necessary for later resolving, typechecking, linking,
// etc.
pub fn read_crates(&mut self, krate: &ast::Crate) {
self.process_crate(krate);
visit::walk_crate(self, krate);

if log_enabled!(log::DEBUG) {
dump_crates(&self.sess.cstore);
}

for &(ref name, kind) in &self.sess.opts.libs {
register_native_lib(self.sess, None, name.clone(), kind);
}
}

fn process_crate(&self, c: &ast::Crate) {
for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
match a.value_str() {
Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
None => { /* fallthrough */ }
}
}
}

fn process_item(&mut self, i: &ast::Item) {
match i.node {
ast::ItemExternCrate(_) => {
if !should_link(i) {
return;
}

match self.creader.extract_crate_info(i) {
Some(info) => {
let (cnum, cmeta, _) = self.creader.resolve_crate(&None,
&info.ident,
&info.name,
None,
i.span,
PathKind::Crate);
self.ast_map.with_path(i.id, |path|
cmeta.update_local_path(path));
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
}
None => ()
}
}
ast::ItemForeignMod(ref fm) => {
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic {
return;
}

// First, add all of the custom link_args attributes
let link_args = i.attrs.iter()
.filter_map(|at| if at.name() == "link_args" {
Some(at)
} else {
None
})
.collect::<Vec<&ast::Attribute>>();
for m in &link_args {
match m.value_str() {
Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
None => { /* fallthrough */ }
}
}

// Next, process all of the #[link(..)]-style arguments
let link_args = i.attrs.iter()
.filter_map(|at| if at.name() == "link" {
Some(at)
} else {
None
})
.collect::<Vec<&ast::Attribute>>();
for m in &link_args {
match m.meta_item_list() {
Some(items) => {
let kind = items.iter().find(|k| {
k.name() == "kind"
}).and_then(|a| a.value_str());
let kind = match kind {
Some(k) => {
if k == "static" {
cstore::NativeStatic
} else if self.sess.target.target.options.is_like_osx
&& k == "framework" {
cstore::NativeFramework
} else if k == "framework" {
cstore::NativeFramework
} else if k == "dylib" {
cstore::NativeUnknown
} else {
self.sess.span_err(m.span,
&format!("unknown kind: `{}`",
k));
cstore::NativeUnknown
}
}
None => cstore::NativeUnknown
};
let n = items.iter().find(|n| {
n.name() == "name"
}).and_then(|a| a.value_str());
let n = match n {
Some(n) => n,
None => {
self.sess.span_err(m.span,
"#[link(...)] specified without \
`name = \"foo\"`");
InternedString::new("foo")
}
};
register_native_lib(self.sess, Some(m.span),
n.to_string(), kind);
}
None => {}
}
}
}
_ => { }
}
}
}

/// Imports the codemap from an external crate into the codemap of the crate
/// currently being compiled (the "local crate").
///
Expand Down
12 changes: 6 additions & 6 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use syntax::ast;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::diagnostic::expect;
use syntax::parse::token;

use std::collections::hash_map::HashMap;

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

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

pub enum FoundAst<'ast> {
Expand Down
28 changes: 28 additions & 0 deletions src/librustc/metadata/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ use std::path::PathBuf;
use flate::Bytes;
use syntax::ast;
use syntax::codemap;
use syntax::parse::token;
use syntax::parse::token::IdentInterner;
use syntax::util::small_vector::SmallVector;
use ast_map;

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

pub struct crate_metadata {
pub name: String,
pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
pub data: MetadataBlob,
pub cnum_map: cnum_map,
pub cnum: ast::CrateNum,
Expand Down Expand Up @@ -255,6 +259,30 @@ impl crate_metadata {
filemaps
}
}
pub fn with_local_path<T, F>(&self, f: F) -> T
where F: Fn(&[ast_map::PathElem]) -> T {
let cpath = self.local_path.borrow();
if cpath.is_empty() {
let name = ast_map::PathMod(token::intern(&self.name));
f(&[name])
} else {
f(cpath.as_slice())
}
}
pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) {
let mut cpath = self.local_path.borrow_mut();
let cap = cpath.len();
match cap {
0 => *cpath = candidate.collect(),
1 => (),
_ => {
let candidate: SmallVector<_> = candidate.collect();
if candidate.len() < cap {
*cpath = candidate;
}
},
}
}
}

impl MetadataBlob {
Expand Down
Loading

0 comments on commit 0dc2910

Please sign in to comment.