提交 0dc2910c 编写于 作者: B bors

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 
......@@ -34,14 +34,22 @@
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);
......@@ -152,31 +160,6 @@ pub fn new(sess: &'a Session) -> 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) => {
......@@ -201,103 +184,6 @@ fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
}
}
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;
......@@ -378,6 +264,7 @@ fn register_crate(&mut self,
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,
......@@ -592,6 +479,140 @@ pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
}
}
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").
///
......
......@@ -24,7 +24,6 @@
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::diagnostic::expect;
use syntax::parse::token;
use std::collections::hash_map::HashMap;
......@@ -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> {
......
......@@ -28,7 +28,10 @@
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
......@@ -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,
......@@ -255,6 +259,30 @@ pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
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 {
......
......@@ -14,7 +14,7 @@
use rustc::ast_map;
use rustc::lint;
use rustc::metadata;
use rustc::metadata::creader::CrateReader;
use rustc::metadata::creader::LocalCrateReader;
use rustc::middle::{stability, ty, reachable};
use rustc::middle::dependency_format;
use rustc::middle;
......@@ -609,7 +609,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
let krate = ast_map.krate();
time(time_passes, "external crate/lib resolution", (), |_|
CrateReader::new(&sess).read_crates(krate));
LocalCrateReader::new(&sess, &ast_map).read_crates(krate));
let lang_items = time(time_passes, "language item collection", (), |_|
middle::lang_items::collect_language_items(krate, &sess));
......
......@@ -15,7 +15,7 @@
#[bench]
fn bar(x: isize) { }
//~^ ERROR mismatched types
//~| expected `fn(&mut test::Bencher)`
//~| expected `fn(&mut __test::test::Bencher)`
//~| found `fn(isize) {bar}`
//~| expected &-ptr
//~| found isize
// 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.
//! Test that absolute path names are correct when a crate is not linked into the root namespace
mod foo {
extern crate core;
}
fn assert_clone<T>() where T : Clone { }
fn main() {
assert_clone::<foo::core::atomic::AtomicBool>();
//~^ ERROR the trait `foo::core::clone::Clone` is not implemented for the type `foo::core::
}
\ No newline at end of file
// 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.
//! Test that when a crate is linked under another name that that name is used in global paths
extern crate core as bar;
fn assert_clone<T>() where T : Clone { }
fn main() {
assert_clone::<bar::atomic::AtomicBool>();
//~^ ERROR the trait `bar::clone::Clone` is not implemented for the type `bar::atomic::
}
\ No newline at end of file
// 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.
//! Test that when a crate is linked multiple times that the shortest absolute path name is used
mod foo {
extern crate core;
}
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::
}
\ No newline at end of file
......@@ -101,30 +101,30 @@ fn xcrate() {
let c = other::C(2, 3); //~ ERROR: cannot invoke tuple struct constructor
let d = other::D(4);
let other::A(()) = a; //~ ERROR: field #1 of struct `privacy_tuple_struct::A` is private
let other::A(()) = a; //~ ERROR: field #1 of struct `other::A` is private
let other::A(_) = a;
match a { other::A(()) => {} }
//~^ ERROR: field #1 of struct `privacy_tuple_struct::A` is private
//~^ ERROR: field #1 of struct `other::A` is private
match a { other::A(_) => {} }
let other::B(_) = b;
let other::B(_b) = b; //~ ERROR: field #1 of struct `privacy_tuple_struct::B` is private
let other::B(_b) = b; //~ ERROR: field #1 of struct `other::B` is private
match b { other::B(_) => {} }
match b { other::B(_b) => {} }
//~^ ERROR: field #1 of struct `privacy_tuple_struct::B` is private
//~^ ERROR: field #1 of struct `other::B` is private
match b { other::B(1) => {} other::B(_) => {} }
//~^ ERROR: field #1 of struct `privacy_tuple_struct::B` is private
//~^ ERROR: field #1 of struct `other::B` is private
let other::C(_, _) = c;
let other::C(_a, _) = c;
let other::C(_, _b) = c; //~ ERROR: field #2 of struct `privacy_tuple_struct::C` is private
let other::C(_a, _b) = c; //~ ERROR: field #2 of struct `privacy_tuple_struct::C` is private
let other::C(_, _b) = c; //~ ERROR: field #2 of struct `other::C` is private
let other::C(_a, _b) = c; //~ ERROR: field #2 of struct `other::C` is private
match c { other::C(_, _) => {} }
match c { other::C(_a, _) => {} }
match c { other::C(_, _b) => {} }
//~^ ERROR: field #2 of struct `privacy_tuple_struct::C` is private
//~^ ERROR: field #2 of struct `other::C` is private
match c { other::C(_a, _b) => {} }
//~^ ERROR: field #2 of struct `privacy_tuple_struct::C` is private
//~^ ERROR: field #2 of struct `other::C` is private
let other::D(_) = d;
let other::D(_d) = d;
......
......@@ -37,11 +37,11 @@ fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B) {
c.a;
c.b; //~ ERROR: field `b` of struct `inner::B` is private
d.a; //~ ERROR: field `a` of struct `struct_field_privacy::A` is private
d.a; //~ ERROR: field `a` of struct `xc::A` is private
d.b;
e.a;
e.b; //~ ERROR: field `b` of struct `struct_field_privacy::B` is private
e.b; //~ ERROR: field `b` of struct `xc::B` is private
}
fn main() {}
......@@ -22,9 +22,9 @@ struct A {
fn main () {
// external crate struct
let k = B {
aa: 20, //~ ERROR structure `struct_field_privacy::B` has no field named `aa`
aa: 20, //~ ERROR structure `xc::B` has no field named `aa`
//~^ HELP did you mean `a`?
bb: 20, //~ ERROR structure `struct_field_privacy::B` has no field named `bb`
bb: 20, //~ ERROR structure `xc::B` has no field named `bb`
};
// local crate struct
let l = A {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册