Skip to content

Include crate-local paths to extern crates in absolute paths #27458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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