2015-02-05 14:28:17 -06:00
|
|
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2014-03-21 20:05:05 -05:00
|
|
|
#![allow(non_camel_case_types)]
|
2014-02-10 08:36:31 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
//! Validates all used crates and extern libraries and loads their metadata
|
2011-03-15 18:30:43 -05:00
|
|
|
|
2014-02-24 21:45:20 -06:00
|
|
|
use back::svh::Svh;
|
2014-11-15 19:30:33 -06:00
|
|
|
use session::{config, Session};
|
2014-12-16 16:32:02 -06:00
|
|
|
use session::search_paths::PathKind;
|
2015-09-27 23:31:45 -05:00
|
|
|
use metadata::common::rustc_version;
|
2012-12-23 16:41:37 -06:00
|
|
|
use metadata::cstore;
|
2014-12-31 21:48:39 -06:00
|
|
|
use metadata::cstore::{CStore, CrateSource, MetadataBlob};
|
2012-12-23 16:41:37 -06:00
|
|
|
use metadata::decoder;
|
|
|
|
use metadata::loader;
|
2014-04-03 10:43:57 -05:00
|
|
|
use metadata::loader::CratePaths;
|
2015-07-30 16:20:36 -05:00
|
|
|
use util::nodemap::FnvHashMap;
|
2015-07-31 02:04:06 -05:00
|
|
|
use front::map as hir_map;
|
2012-12-23 16:41:37 -06:00
|
|
|
|
2015-06-25 12:07:01 -05:00
|
|
|
use std::cell::{RefCell, Cell};
|
2015-04-16 01:21:13 -05:00
|
|
|
use std::path::PathBuf;
|
2014-03-27 12:28:38 -05:00
|
|
|
use std::rc::Rc;
|
2015-04-16 01:21:13 -05:00
|
|
|
use std::fs;
|
|
|
|
|
2013-07-19 20:42:11 -05:00
|
|
|
use syntax::ast;
|
2013-11-30 13:39:55 -06:00
|
|
|
use syntax::abi;
|
2015-02-11 11:29:49 -06:00
|
|
|
use syntax::codemap::{self, Span, mk_sp, Pos};
|
2014-12-30 21:10:46 -06:00
|
|
|
use syntax::parse;
|
2015-07-31 02:04:06 -05:00
|
|
|
use syntax::attr;
|
2015-09-14 04:58:20 -05:00
|
|
|
use syntax::attr::AttrMetaMethods;
|
2014-04-17 10:52:25 -05:00
|
|
|
use syntax::parse::token::InternedString;
|
2015-08-01 09:14:45 -05:00
|
|
|
use syntax::util::small_vector::SmallVector;
|
2015-07-31 02:04:06 -05:00
|
|
|
use rustc_front::visit;
|
|
|
|
use rustc_front::hir;
|
2014-12-21 00:36:50 -06:00
|
|
|
use log;
|
2011-03-15 18:30:43 -05:00
|
|
|
|
2015-07-30 14:59:42 -05:00
|
|
|
pub struct LocalCrateReader<'a, 'b:'a> {
|
|
|
|
sess: &'a Session,
|
|
|
|
creader: CrateReader<'a>,
|
2015-07-31 02:04:06 -05:00
|
|
|
ast_map: &'a hir_map::Map<'b>,
|
2015-07-30 14:59:42 -05:00
|
|
|
}
|
|
|
|
|
2014-12-21 01:02:38 -06:00
|
|
|
pub struct CrateReader<'a> {
|
2014-04-07 14:14:33 -05:00
|
|
|
sess: &'a Session,
|
|
|
|
next_crate_num: ast::CrateNum,
|
2015-07-30 16:20:36 -05:00
|
|
|
foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>,
|
2014-04-07 14:14:33 -05:00
|
|
|
}
|
|
|
|
|
2015-07-30 14:59:42 -05:00
|
|
|
impl<'a, 'b, 'v> visit::Visitor<'v> for LocalCrateReader<'a, 'b> {
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_item(&mut self, a: &hir::Item) {
|
2014-12-21 00:36:50 -06:00
|
|
|
self.process_item(a);
|
2014-09-12 05:10:30 -05:00
|
|
|
visit::walk_item(self, a);
|
2013-08-26 04:01:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-07 14:14:33 -05:00
|
|
|
fn dump_crates(cstore: &CStore) {
|
2015-06-25 12:07:01 -05:00
|
|
|
info!("resolved crates:");
|
2014-04-25 11:06:49 -05:00
|
|
|
cstore.iter_crate_data_origins(|_, data, opt_source| {
|
2015-06-25 12:07:01 -05:00
|
|
|
info!(" name: {}", data.name());
|
|
|
|
info!(" cnum: {}", data.cnum);
|
|
|
|
info!(" hash: {}", data.hash());
|
|
|
|
info!(" reqd: {}", data.explicitly_linked.get());
|
2014-04-25 11:06:49 -05:00
|
|
|
opt_source.map(|cs| {
|
|
|
|
let CrateSource { dylib, rlib, cnum: _ } = cs;
|
2015-06-25 12:07:01 -05:00
|
|
|
dylib.map(|dl| info!(" dylib: {}", dl.0.display()));
|
|
|
|
rlib.map(|rl| info!(" rlib: {}", rl.0.display()));
|
2014-04-25 11:06:49 -05:00
|
|
|
});
|
2014-04-07 14:14:33 -05:00
|
|
|
})
|
2012-04-09 17:06:38 -05:00
|
|
|
}
|
|
|
|
|
2014-12-23 13:33:44 -06:00
|
|
|
fn should_link(i: &ast::Item) -> bool {
|
2015-02-20 13:08:14 -06:00
|
|
|
!attr::contains_name(&i.attrs, "no_link")
|
2014-04-07 14:16:43 -05:00
|
|
|
}
|
2015-07-31 02:04:06 -05:00
|
|
|
// Dup for the hir
|
|
|
|
fn should_link_hir(i: &hir::Item) -> bool {
|
2015-09-14 04:58:20 -05:00
|
|
|
!attr::contains_name(&i.attrs, "no_link")
|
2015-07-31 02:04:06 -05:00
|
|
|
}
|
|
|
|
|
2013-12-25 12:10:33 -06:00
|
|
|
struct CrateInfo {
|
2014-05-22 18:57:53 -05:00
|
|
|
ident: String,
|
2014-06-06 15:21:18 -05:00
|
|
|
name: String,
|
2013-12-25 12:10:33 -06:00
|
|
|
id: ast::NodeId,
|
2014-04-07 14:16:43 -05:00
|
|
|
should_link: bool,
|
2013-12-25 12:10:33 -06:00
|
|
|
}
|
|
|
|
|
2014-06-06 15:21:18 -05:00
|
|
|
pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
|
2015-03-26 19:35:13 -05:00
|
|
|
let say = |s: &str| {
|
2014-06-06 15:21:18 -05:00
|
|
|
match (sp, sess) {
|
2014-10-09 14:17:22 -05:00
|
|
|
(_, None) => panic!("{}", s),
|
2014-06-06 15:21:18 -05:00
|
|
|
(Some(sp), Some(sess)) => sess.span_err(sp, s),
|
|
|
|
(None, Some(sess)) => sess.err(s),
|
|
|
|
}
|
|
|
|
};
|
2015-03-24 18:53:34 -05:00
|
|
|
if s.is_empty() {
|
2015-03-26 19:35:13 -05:00
|
|
|
say("crate name must not be empty");
|
2014-06-06 15:21:18 -05:00
|
|
|
}
|
|
|
|
for c in s.chars() {
|
|
|
|
if c.is_alphanumeric() { continue }
|
2015-03-26 19:35:13 -05:00
|
|
|
if c == '_' { continue }
|
|
|
|
say(&format!("invalid character `{}` in crate name: `{}`", c, s));
|
2014-06-06 15:21:18 -05:00
|
|
|
}
|
|
|
|
match sess {
|
|
|
|
Some(sess) => sess.abort_if_errors(),
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 18:56:28 -06:00
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
fn register_native_lib(sess: &Session,
|
|
|
|
span: Option<Span>,
|
|
|
|
name: String,
|
|
|
|
kind: cstore::NativeLibraryKind) {
|
2014-11-27 12:53:34 -06:00
|
|
|
if name.is_empty() {
|
2014-10-21 01:04:16 -05:00
|
|
|
match span {
|
|
|
|
Some(span) => {
|
2015-09-11 09:17:15 -05:00
|
|
|
span_err!(sess, span, E0454,
|
|
|
|
"#[link(name = \"\")] given with empty name");
|
2014-10-21 01:04:16 -05:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
sess.err("empty library name given via `-l`");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2014-07-23 13:56:36 -05:00
|
|
|
let is_osx = sess.target.target.options.is_like_osx;
|
2014-10-21 01:04:16 -05:00
|
|
|
if kind == cstore::NativeFramework && !is_osx {
|
|
|
|
let msg = "native frameworks are only available on OSX targets";
|
|
|
|
match span {
|
2015-09-11 09:17:15 -05:00
|
|
|
Some(span) => {
|
|
|
|
span_err!(sess, span, E0455,
|
|
|
|
"{}", msg)
|
|
|
|
}
|
2014-10-21 01:04:16 -05:00
|
|
|
None => sess.err(msg),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sess.cstore.add_used_library(name, kind);
|
|
|
|
}
|
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
// Extra info about a crate loaded for plugins or exported macros.
|
|
|
|
struct ExtensionCrate {
|
2014-12-31 21:48:39 -06:00
|
|
|
metadata: PMDSource,
|
2015-02-26 23:00:43 -06:00
|
|
|
dylib: Option<PathBuf>,
|
2014-12-31 21:48:39 -06:00
|
|
|
target_only: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum PMDSource {
|
|
|
|
Registered(Rc<cstore::crate_metadata>),
|
|
|
|
Owned(MetadataBlob),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PMDSource {
|
|
|
|
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
|
|
|
|
match *self {
|
|
|
|
PMDSource::Registered(ref cmd) => cmd.data(),
|
|
|
|
PMDSource::Owned(ref mdb) => mdb.as_slice(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-21 01:02:38 -06:00
|
|
|
impl<'a> CrateReader<'a> {
|
|
|
|
pub fn new(sess: &'a Session) -> CrateReader<'a> {
|
|
|
|
CrateReader {
|
|
|
|
sess: sess,
|
|
|
|
next_crate_num: sess.cstore.next_crate_num(),
|
2015-07-30 16:20:36 -05:00
|
|
|
foreign_item_map: FnvHashMap(),
|
2014-12-21 01:02:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-23 13:33:44 -06:00
|
|
|
fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
|
2014-12-21 00:36:50 -06:00
|
|
|
match i.node {
|
2014-12-23 13:33:44 -06:00
|
|
|
ast::ItemExternCrate(ref path_opt) => {
|
2015-01-06 18:16:35 -06:00
|
|
|
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
|
2015-07-28 11:07:20 -05:00
|
|
|
i.ident, path_opt);
|
2014-12-21 00:36:50 -06:00
|
|
|
let name = match *path_opt {
|
2015-03-19 17:39:03 -05:00
|
|
|
Some(name) => {
|
2015-07-28 11:07:20 -05:00
|
|
|
validate_crate_name(Some(self.sess), &name.as_str(),
|
2014-12-21 00:36:50 -06:00
|
|
|
Some(i.span));
|
2015-07-28 11:07:20 -05:00
|
|
|
name.to_string()
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
2015-07-28 11:07:20 -05:00
|
|
|
None => i.ident.to_string(),
|
2014-12-21 00:36:50 -06:00
|
|
|
};
|
|
|
|
Some(CrateInfo {
|
2015-07-28 11:07:20 -05:00
|
|
|
ident: i.ident.to_string(),
|
2014-12-21 00:36:50 -06:00
|
|
|
name: name,
|
2014-12-23 13:33:44 -06:00
|
|
|
id: i.id,
|
2014-12-21 00:36:50 -06:00
|
|
|
should_link: should_link(i),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
_ => None
|
2014-07-01 10:37:54 -05:00
|
|
|
}
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
// Dup of the above, but for the hir
|
|
|
|
fn extract_crate_info_hir(&self, i: &hir::Item) -> Option<CrateInfo> {
|
|
|
|
match i.node {
|
|
|
|
hir::ItemExternCrate(ref path_opt) => {
|
|
|
|
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
|
2015-09-19 20:50:30 -05:00
|
|
|
i.name, path_opt);
|
2015-07-31 02:04:06 -05:00
|
|
|
let name = match *path_opt {
|
|
|
|
Some(name) => {
|
|
|
|
validate_crate_name(Some(self.sess), &name.as_str(),
|
|
|
|
Some(i.span));
|
|
|
|
name.to_string()
|
|
|
|
}
|
2015-09-19 20:50:30 -05:00
|
|
|
None => i.name.to_string(),
|
2015-07-31 02:04:06 -05:00
|
|
|
};
|
|
|
|
Some(CrateInfo {
|
2015-09-19 20:50:30 -05:00
|
|
|
ident: i.name.to_string(),
|
2015-07-31 02:04:06 -05:00
|
|
|
name: name,
|
|
|
|
id: i.id,
|
|
|
|
should_link: should_link_hir(i),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-06 10:46:07 -06:00
|
|
|
fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
|
|
|
|
-> Option<ast::CrateNum> {
|
2014-12-21 00:36:50 -06:00
|
|
|
let mut ret = None;
|
|
|
|
self.sess.cstore.iter_crate_data(|cnum, data| {
|
2015-03-26 19:35:13 -05:00
|
|
|
if data.name != name { return }
|
2014-12-21 00:36:50 -06:00
|
|
|
|
|
|
|
match hash {
|
|
|
|
Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
|
|
|
|
Some(..) => return,
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
|
2015-01-06 10:46:07 -06:00
|
|
|
// When the hash is None we're dealing with a top-level dependency
|
|
|
|
// in which case we may have a specification on the command line for
|
|
|
|
// this library. Even though an upstream library may have loaded
|
|
|
|
// something of the same name, we have to make sure it was loaded
|
|
|
|
// from the exact same location as well.
|
2014-12-21 00:36:50 -06:00
|
|
|
//
|
|
|
|
// We're also sure to compare *paths*, not actual byte slices. The
|
|
|
|
// `source` stores paths which are normalized which may be different
|
|
|
|
// from the strings on the command line.
|
|
|
|
let source = self.sess.cstore.get_used_crate_source(cnum).unwrap();
|
2015-01-06 10:46:07 -06:00
|
|
|
if let Some(locs) = self.sess.opts.externs.get(name) {
|
|
|
|
let found = locs.iter().any(|l| {
|
2015-04-16 01:21:13 -05:00
|
|
|
let l = fs::canonicalize(l).ok();
|
2015-01-06 10:46:07 -06:00
|
|
|
source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
|
|
|
|
source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
|
|
|
|
});
|
|
|
|
if found {
|
|
|
|
ret = Some(cnum);
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
2015-01-30 11:48:23 -06:00
|
|
|
return
|
2015-01-06 10:46:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Alright, so we've gotten this far which means that `data` has the
|
|
|
|
// right name, we don't have a hash, and we don't have a --extern
|
|
|
|
// pointing for ourselves. We're still not quite yet done because we
|
|
|
|
// have to make sure that this crate was found in the crate lookup
|
|
|
|
// path (this is a top-level dependency) as we don't want to
|
|
|
|
// implicitly load anything inside the dependency lookup path.
|
|
|
|
let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref())
|
|
|
|
.unwrap().1;
|
|
|
|
if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) {
|
|
|
|
ret = Some(cnum);
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2015-09-27 23:31:45 -05:00
|
|
|
fn verify_rustc_version(&self,
|
|
|
|
name: &str,
|
|
|
|
span: Span,
|
|
|
|
metadata: &MetadataBlob) {
|
|
|
|
let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice());
|
|
|
|
if crate_rustc_version != Some(rustc_version()) {
|
|
|
|
span_err!(self.sess, span, E0514,
|
|
|
|
"the crate `{}` has been compiled with {}, which is \
|
|
|
|
incompatible with this version of rustc",
|
|
|
|
name,
|
|
|
|
crate_rustc_version
|
|
|
|
.as_ref().map(|s|&**s)
|
|
|
|
.unwrap_or("an old version of rustc")
|
|
|
|
);
|
|
|
|
self.sess.abort_if_errors();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
fn register_crate(&mut self,
|
|
|
|
root: &Option<CratePaths>,
|
|
|
|
ident: &str,
|
|
|
|
name: &str,
|
|
|
|
span: Span,
|
2015-06-25 12:07:01 -05:00
|
|
|
lib: loader::Library,
|
|
|
|
explicitly_linked: bool)
|
2014-12-21 00:36:50 -06:00
|
|
|
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
|
|
|
cstore::CrateSource) {
|
2015-09-27 23:31:45 -05:00
|
|
|
self.verify_rustc_version(name, span, &lib.metadata);
|
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
// Claim this crate number and cache it
|
|
|
|
let cnum = self.next_crate_num;
|
|
|
|
self.next_crate_num += 1;
|
|
|
|
|
|
|
|
// Stash paths for top-most crate locally if necessary.
|
|
|
|
let crate_paths = if root.is_none() {
|
|
|
|
Some(CratePaths {
|
|
|
|
ident: ident.to_string(),
|
2015-01-06 10:46:07 -06:00
|
|
|
dylib: lib.dylib.clone().map(|p| p.0),
|
|
|
|
rlib: lib.rlib.clone().map(|p| p.0),
|
2014-12-21 00:36:50 -06:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
// Maintain a reference to the top most crate.
|
|
|
|
let root = if root.is_some() { root } else { &crate_paths };
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2015-02-11 11:29:49 -06:00
|
|
|
let loader::Library { dylib, rlib, metadata } = lib;
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2015-02-11 11:29:49 -06:00
|
|
|
let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span);
|
2015-08-05 20:25:33 -05:00
|
|
|
let staged_api = self.is_staged_api(metadata.as_slice());
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2015-06-25 12:07:01 -05:00
|
|
|
let cmeta = Rc::new(cstore::crate_metadata {
|
2014-12-21 00:36:50 -06:00
|
|
|
name: name.to_string(),
|
2015-08-01 09:14:45 -05:00
|
|
|
local_path: RefCell::new(SmallVector::zero()),
|
2015-09-17 13:29:59 -05:00
|
|
|
local_def_path: RefCell::new(vec![]),
|
2015-09-02 17:22:31 -05:00
|
|
|
index: decoder::load_index(metadata.as_slice()),
|
2015-09-17 08:04:18 -05:00
|
|
|
xref_index: decoder::load_xrefs(metadata.as_slice()),
|
2014-12-21 00:36:50 -06:00
|
|
|
data: metadata,
|
2015-06-25 12:07:01 -05:00
|
|
|
cnum_map: RefCell::new(cnum_map),
|
2014-12-21 00:36:50 -06:00
|
|
|
cnum: cnum,
|
2015-05-22 08:15:21 -05:00
|
|
|
codemap_import_info: RefCell::new(vec![]),
|
2014-12-21 00:36:50 -06:00
|
|
|
span: span,
|
2015-06-25 12:07:01 -05:00
|
|
|
staged_api: staged_api,
|
|
|
|
explicitly_linked: Cell::new(explicitly_linked),
|
2014-12-21 00:36:50 -06:00
|
|
|
});
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
let source = cstore::CrateSource {
|
|
|
|
dylib: dylib,
|
|
|
|
rlib: rlib,
|
|
|
|
cnum: cnum,
|
|
|
|
};
|
|
|
|
|
|
|
|
self.sess.cstore.set_crate_data(cnum, cmeta.clone());
|
|
|
|
self.sess.cstore.add_used_crate_source(source.clone());
|
|
|
|
(cnum, cmeta, source)
|
|
|
|
}
|
2014-04-17 10:52:25 -05:00
|
|
|
|
2015-08-05 20:25:33 -05:00
|
|
|
fn is_staged_api(&self, data: &[u8]) -> bool {
|
|
|
|
let attrs = decoder::get_crate_attributes(data);
|
|
|
|
for attr in &attrs {
|
|
|
|
if &attr.name()[..] == "staged_api" {
|
2015-09-14 04:58:20 -05:00
|
|
|
match attr.node.value.node { ast::MetaWord(_) => return true, _ => (/*pass*/) }
|
2015-08-05 20:25:33 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
fn resolve_crate(&mut self,
|
|
|
|
root: &Option<CratePaths>,
|
|
|
|
ident: &str,
|
|
|
|
name: &str,
|
|
|
|
hash: Option<&Svh>,
|
|
|
|
span: Span,
|
2015-06-25 12:07:01 -05:00
|
|
|
kind: PathKind,
|
|
|
|
explicitly_linked: bool)
|
2014-12-21 00:36:50 -06:00
|
|
|
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
|
|
|
|
cstore::CrateSource) {
|
2015-01-06 10:46:07 -06:00
|
|
|
match self.existing_match(name, hash, kind) {
|
2014-12-21 00:36:50 -06:00
|
|
|
None => {
|
|
|
|
let mut load_ctxt = loader::Context {
|
|
|
|
sess: self.sess,
|
|
|
|
span: span,
|
|
|
|
ident: ident,
|
|
|
|
crate_name: name,
|
|
|
|
hash: hash.map(|a| &*a),
|
|
|
|
filesearch: self.sess.target_filesearch(kind),
|
2015-01-08 19:14:10 -06:00
|
|
|
target: &self.sess.target.target,
|
2015-02-20 13:08:14 -06:00
|
|
|
triple: &self.sess.opts.target_triple,
|
2014-12-21 00:36:50 -06:00
|
|
|
root: root,
|
|
|
|
rejected_via_hash: vec!(),
|
|
|
|
rejected_via_triple: vec!(),
|
2015-02-05 14:28:17 -06:00
|
|
|
rejected_via_kind: vec!(),
|
2014-12-21 00:36:50 -06:00
|
|
|
should_match_name: true,
|
|
|
|
};
|
|
|
|
let library = load_ctxt.load_library_crate();
|
2015-06-25 12:07:01 -05:00
|
|
|
self.register_crate(root, ident, name, span, library,
|
|
|
|
explicitly_linked)
|
|
|
|
}
|
|
|
|
Some(cnum) => {
|
|
|
|
let data = self.sess.cstore.get_crate_data(cnum);
|
|
|
|
if explicitly_linked && !data.explicitly_linked.get() {
|
|
|
|
data.explicitly_linked.set(explicitly_linked);
|
|
|
|
}
|
|
|
|
(cnum, data, self.sess.cstore.get_used_crate_source(cnum).unwrap())
|
2014-12-21 00:36:50 -06:00
|
|
|
}
|
2014-02-24 20:13:51 -06:00
|
|
|
}
|
2012-04-05 20:31:03 -05:00
|
|
|
}
|
2011-05-26 19:16:54 -05:00
|
|
|
|
2014-12-21 00:36:50 -06:00
|
|
|
// Go through the crate metadata and load any crates that it references
|
|
|
|
fn resolve_crate_deps(&mut self,
|
|
|
|
root: &Option<CratePaths>,
|
|
|
|
cdata: &[u8], span : Span)
|
|
|
|
-> cstore::cnum_map {
|
|
|
|
debug!("resolving deps of external crate");
|
|
|
|
// The map from crate numbers in the crate we're resolving to local crate
|
|
|
|
// numbers
|
|
|
|
decoder::get_crate_deps(cdata).iter().map(|dep| {
|
|
|
|
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
|
|
|
|
let (local_cnum, _, _) = self.resolve_crate(root,
|
2015-02-20 13:08:14 -06:00
|
|
|
&dep.name,
|
|
|
|
&dep.name,
|
2014-12-21 00:36:50 -06:00
|
|
|
Some(&dep.hash),
|
|
|
|
span,
|
2015-06-25 12:07:01 -05:00
|
|
|
PathKind::Dependency,
|
|
|
|
dep.explicitly_linked);
|
2014-12-21 00:36:50 -06:00
|
|
|
(dep.cnum, local_cnum)
|
|
|
|
}).collect()
|
|
|
|
}
|
2013-12-25 12:10:33 -06:00
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate {
|
2015-02-20 13:08:14 -06:00
|
|
|
let target_triple = &self.sess.opts.target_triple[..];
|
2014-11-15 19:30:33 -06:00
|
|
|
let is_cross = target_triple != config::host_triple();
|
2014-04-17 10:52:25 -05:00
|
|
|
let mut should_link = info.should_link && !is_cross;
|
2014-12-31 21:48:39 -06:00
|
|
|
let mut target_only = false;
|
|
|
|
let ident = info.ident.clone();
|
|
|
|
let name = info.name.clone();
|
2014-04-17 10:52:25 -05:00
|
|
|
let mut load_ctxt = loader::Context {
|
2014-12-21 01:02:38 -06:00
|
|
|
sess: self.sess,
|
2014-12-09 10:03:05 -06:00
|
|
|
span: span,
|
2015-02-18 13:48:57 -06:00
|
|
|
ident: &ident[..],
|
|
|
|
crate_name: &name[..],
|
2014-04-17 10:52:25 -05:00
|
|
|
hash: None,
|
2014-12-21 01:02:38 -06:00
|
|
|
filesearch: self.sess.host_filesearch(PathKind::Crate),
|
2015-01-08 19:14:10 -06:00
|
|
|
target: &self.sess.host,
|
2014-11-15 19:30:33 -06:00
|
|
|
triple: config::host_triple(),
|
2014-04-17 10:52:25 -05:00
|
|
|
root: &None,
|
|
|
|
rejected_via_hash: vec!(),
|
|
|
|
rejected_via_triple: vec!(),
|
2015-02-05 14:28:17 -06:00
|
|
|
rejected_via_kind: vec!(),
|
2014-07-01 10:37:54 -05:00
|
|
|
should_match_name: true,
|
2014-04-17 10:52:25 -05:00
|
|
|
};
|
|
|
|
let library = match load_ctxt.maybe_load_library_crate() {
|
2014-07-09 21:13:28 -05:00
|
|
|
Some(l) => l,
|
2014-04-17 10:52:25 -05:00
|
|
|
None if is_cross => {
|
2015-01-06 10:46:07 -06:00
|
|
|
// Try loading from target crates. This will abort later if we
|
|
|
|
// try to load a plugin registrar function,
|
2014-12-31 21:48:39 -06:00
|
|
|
target_only = true;
|
|
|
|
should_link = info.should_link;
|
|
|
|
|
2015-01-08 19:14:10 -06:00
|
|
|
load_ctxt.target = &self.sess.target.target;
|
2014-04-17 10:52:25 -05:00
|
|
|
load_ctxt.triple = target_triple;
|
2014-12-21 01:02:38 -06:00
|
|
|
load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);
|
2014-12-31 21:48:39 -06:00
|
|
|
load_ctxt.load_library_crate()
|
2014-04-17 10:52:25 -05:00
|
|
|
}
|
|
|
|
None => { load_ctxt.report_load_errs(); unreachable!() },
|
|
|
|
};
|
2014-12-30 21:10:46 -06:00
|
|
|
|
2014-12-31 21:48:39 -06:00
|
|
|
let dylib = library.dylib.clone();
|
2015-03-07 20:08:48 -06:00
|
|
|
let register = should_link && self.existing_match(&info.name,
|
2015-01-06 10:46:07 -06:00
|
|
|
None,
|
|
|
|
PathKind::Crate).is_none();
|
2014-12-31 21:48:39 -06:00
|
|
|
let metadata = if register {
|
|
|
|
// Register crate now to avoid double-reading metadata
|
2015-02-20 13:08:14 -06:00
|
|
|
let (_, cmd, _) = self.register_crate(&None, &info.ident,
|
2015-06-25 12:07:01 -05:00
|
|
|
&info.name, span, library,
|
|
|
|
true);
|
2014-12-31 21:48:39 -06:00
|
|
|
PMDSource::Registered(cmd)
|
|
|
|
} else {
|
|
|
|
// Not registering the crate; just hold on to the metadata
|
|
|
|
PMDSource::Owned(library.metadata)
|
|
|
|
};
|
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
ExtensionCrate {
|
2014-12-31 21:48:39 -06:00
|
|
|
metadata: metadata,
|
2015-01-06 10:46:07 -06:00
|
|
|
dylib: dylib.map(|p| p.0),
|
2014-12-31 21:48:39 -06:00
|
|
|
target_only: target_only,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
/// Read exported macros.
|
2015-07-31 02:04:06 -05:00
|
|
|
pub fn read_exported_macros(&mut self, item: &ast::Item) -> Vec<ast::MacroDef> {
|
|
|
|
let ci = self.extract_crate_info(item).unwrap();
|
|
|
|
let ekrate = self.read_extension_crate(item.span, &ci);
|
2014-12-09 10:03:05 -06:00
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
let source_name = format!("<{} macros>", item.ident);
|
2014-12-30 21:10:46 -06:00
|
|
|
let mut macros = vec![];
|
2015-02-11 20:43:16 -06:00
|
|
|
decoder::each_exported_macro(ekrate.metadata.as_slice(),
|
2014-12-31 21:48:39 -06:00
|
|
|
&*self.sess.cstore.intr,
|
2014-12-30 21:10:46 -06:00
|
|
|
|name, attrs, body| {
|
|
|
|
// NB: Don't use parse::parse_tts_from_source_str because it parses with
|
|
|
|
// quote_depth > 0.
|
|
|
|
let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
|
|
|
|
self.sess.opts.cfg.clone(),
|
|
|
|
source_name.clone(),
|
|
|
|
body);
|
|
|
|
let lo = p.span.lo;
|
2015-03-28 16:58:51 -05:00
|
|
|
let body = match p.parse_all_token_trees() {
|
|
|
|
Ok(body) => body,
|
|
|
|
Err(err) => panic!(err),
|
|
|
|
};
|
2014-12-30 21:10:46 -06:00
|
|
|
let span = mk_sp(lo, p.last_span.hi);
|
|
|
|
p.abort_if_errors();
|
2015-09-28 16:23:54 -05:00
|
|
|
|
|
|
|
// Mark the attrs as used
|
|
|
|
for attr in &attrs {
|
|
|
|
attr::mark_used(attr);
|
|
|
|
}
|
|
|
|
|
2014-12-30 21:10:46 -06:00
|
|
|
macros.push(ast::MacroDef {
|
2015-09-24 15:05:02 -05:00
|
|
|
ident: ast::Ident::with_empty_ctxt(name),
|
2015-09-14 04:58:20 -05:00
|
|
|
attrs: attrs,
|
2014-12-30 21:10:46 -06:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: span,
|
2015-07-31 02:04:06 -05:00
|
|
|
imported_from: Some(item.ident),
|
2015-01-02 14:50:45 -06:00
|
|
|
// overridden in plugin/load.rs
|
|
|
|
export: false,
|
|
|
|
use_locally: false,
|
Add #[allow_internal_unstable] to track stability for macros better.
Unstable items used in a macro expansion will now always trigger
stability warnings, *unless* the unstable items are directly inside a
macro marked with `#[allow_internal_unstable]`. IOW, the compiler warns
unless the span of the unstable item is a subspan of the definition of a
macro marked with that attribute.
E.g.
#[allow_internal_unstable]
macro_rules! foo {
($e: expr) => {{
$e;
unstable(); // no warning
only_called_by_foo!();
}}
}
macro_rules! only_called_by_foo {
() => { unstable() } // warning
}
foo!(unstable()) // warning
The unstable inside `foo` is fine, due to the attribute. But the
`unstable` inside `only_called_by_foo` is not, since that macro doesn't
have the attribute, and the `unstable` passed into `foo` is also not
fine since it isn't contained in the macro itself (that is, even though
it is only used directly in the macro).
In the process this makes the stability tracking much more precise,
e.g. previously `println!("{}", unstable())` got no warning, but now it
does. As such, this is a bug fix that may cause [breaking-change]s.
The attribute is definitely feature gated, since it explicitly allows
side-stepping the feature gating system.
2015-02-28 21:09:28 -06:00
|
|
|
allow_internal_unstable: false,
|
2015-01-02 14:50:45 -06:00
|
|
|
|
2014-12-30 21:10:46 -06:00
|
|
|
body: body,
|
|
|
|
});
|
|
|
|
true
|
|
|
|
}
|
|
|
|
);
|
2014-12-31 21:48:39 -06:00
|
|
|
macros
|
|
|
|
}
|
2014-12-30 21:10:46 -06:00
|
|
|
|
2014-12-31 21:48:39 -06:00
|
|
|
/// Look for a plugin registrar. Returns library path and symbol name.
|
2015-02-26 23:00:43 -06:00
|
|
|
pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
|
|
|
|
-> Option<(PathBuf, String)> {
|
2015-02-11 20:43:16 -06:00
|
|
|
let ekrate = self.read_extension_crate(span, &CrateInfo {
|
|
|
|
name: name.to_string(),
|
|
|
|
ident: name.to_string(),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
should_link: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
if ekrate.target_only {
|
2014-12-31 21:48:39 -06:00
|
|
|
// Need to abort before syntax expansion.
|
2015-02-11 20:43:16 -06:00
|
|
|
let message = format!("plugin `{}` is not available for triple `{}` \
|
2014-12-31 21:48:39 -06:00
|
|
|
(only found {})",
|
2015-02-11 20:43:16 -06:00
|
|
|
name,
|
2014-12-31 21:48:39 -06:00
|
|
|
config::host_triple(),
|
|
|
|
self.sess.opts.target_triple);
|
2015-09-11 09:17:15 -05:00
|
|
|
span_err!(self.sess, span, E0456, "{}", &message[..]);
|
2014-12-31 21:48:39 -06:00
|
|
|
self.sess.abort_if_errors();
|
2014-07-09 21:13:28 -05:00
|
|
|
}
|
2014-12-31 21:48:39 -06:00
|
|
|
|
2015-09-17 13:29:59 -05:00
|
|
|
let registrar =
|
|
|
|
decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
|
2015-09-02 17:22:31 -05:00
|
|
|
.map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id));
|
2014-12-31 21:48:39 -06:00
|
|
|
|
2015-02-11 20:43:16 -06:00
|
|
|
match (ekrate.dylib.as_ref(), registrar) {
|
2015-02-26 23:00:43 -06:00
|
|
|
(Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)),
|
2014-12-31 21:48:39 -06:00
|
|
|
(None, Some(_)) => {
|
2015-09-11 09:17:15 -05:00
|
|
|
span_err!(self.sess, span, E0457,
|
|
|
|
"plugin `{}` only found in rlib format, but must be available \
|
|
|
|
in dylib format",
|
|
|
|
name);
|
2014-12-31 21:48:39 -06:00
|
|
|
// No need to abort because the loading code will just ignore this
|
|
|
|
// empty dylib.
|
|
|
|
None
|
|
|
|
}
|
|
|
|
_ => None,
|
2013-12-25 12:10:33 -06:00
|
|
|
}
|
|
|
|
}
|
2015-07-30 16:20:36 -05:00
|
|
|
|
|
|
|
fn register_statically_included_foreign_items(&mut self) {
|
|
|
|
let libs = self.sess.cstore.get_used_libraries();
|
|
|
|
for (lib, list) in self.foreign_item_map.iter() {
|
|
|
|
let is_static = libs.borrow().iter().any(|&(ref name, kind)| {
|
|
|
|
lib == name && kind == cstore::NativeStatic
|
|
|
|
});
|
|
|
|
if is_static {
|
|
|
|
for id in list {
|
|
|
|
self.sess.cstore.add_statically_included_foreign_item(*id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-25 12:07:01 -05:00
|
|
|
|
|
|
|
fn inject_allocator_crate(&mut self) {
|
|
|
|
// Make sure that we actually need an allocator, if none of our
|
|
|
|
// dependencies need one then we definitely don't!
|
|
|
|
//
|
|
|
|
// Also, if one of our dependencies has an explicit allocator, then we
|
|
|
|
// also bail out as we don't need to implicitly inject one.
|
|
|
|
let mut needs_allocator = false;
|
|
|
|
let mut found_required_allocator = false;
|
|
|
|
self.sess.cstore.iter_crate_data(|cnum, data| {
|
|
|
|
needs_allocator = needs_allocator || data.needs_allocator();
|
|
|
|
if data.is_allocator() {
|
|
|
|
debug!("{} required by rlib and is an allocator", data.name());
|
|
|
|
self.inject_allocator_dependency(cnum);
|
|
|
|
found_required_allocator = found_required_allocator ||
|
|
|
|
data.explicitly_linked.get();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if !needs_allocator || found_required_allocator { return }
|
|
|
|
|
|
|
|
// At this point we've determined that we need an allocator and no
|
|
|
|
// previous allocator has been activated. We look through our outputs of
|
|
|
|
// crate types to see what kind of allocator types we may need.
|
|
|
|
//
|
|
|
|
// The main special output type here is that rlibs do **not** need an
|
|
|
|
// allocator linked in (they're just object files), only final products
|
|
|
|
// (exes, dylibs, staticlibs) need allocators.
|
|
|
|
let mut need_lib_alloc = false;
|
|
|
|
let mut need_exe_alloc = false;
|
|
|
|
for ct in self.sess.crate_types.borrow().iter() {
|
|
|
|
match *ct {
|
|
|
|
config::CrateTypeExecutable => need_exe_alloc = true,
|
|
|
|
config::CrateTypeDylib |
|
|
|
|
config::CrateTypeStaticlib => need_lib_alloc = true,
|
|
|
|
config::CrateTypeRlib => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !need_lib_alloc && !need_exe_alloc { return }
|
|
|
|
|
|
|
|
// The default allocator crate comes from the custom target spec, and we
|
|
|
|
// choose between the standard library allocator or exe allocator. This
|
|
|
|
// distinction exists because the default allocator for binaries (where
|
|
|
|
// the world is Rust) is different than library (where the world is
|
|
|
|
// likely *not* Rust).
|
|
|
|
//
|
|
|
|
// If a library is being produced, but we're also flagged with `-C
|
|
|
|
// prefer-dynamic`, then we interpret this as a *Rust* dynamic library
|
|
|
|
// is being produced so we use the exe allocator instead.
|
|
|
|
//
|
|
|
|
// What this boils down to is:
|
|
|
|
//
|
|
|
|
// * Binaries use jemalloc
|
|
|
|
// * Staticlibs and Rust dylibs use system malloc
|
|
|
|
// * Rust dylibs used as dependencies to rust use jemalloc
|
|
|
|
let name = if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
|
|
|
|
&self.sess.target.target.options.lib_allocation_crate
|
|
|
|
} else {
|
|
|
|
&self.sess.target.target.options.exe_allocation_crate
|
|
|
|
};
|
|
|
|
let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
|
|
|
|
codemap::DUMMY_SP,
|
|
|
|
PathKind::Crate, false);
|
|
|
|
|
|
|
|
// To ensure that the `-Z allocation-crate=foo` option isn't abused, and
|
|
|
|
// to ensure that the allocator is indeed an allocator, we verify that
|
|
|
|
// the crate loaded here is indeed tagged #![allocator].
|
|
|
|
if !data.is_allocator() {
|
|
|
|
self.sess.err(&format!("the allocator crate `{}` is not tagged \
|
|
|
|
with #![allocator]", data.name()));
|
|
|
|
}
|
|
|
|
|
|
|
|
self.sess.injected_allocator.set(Some(cnum));
|
|
|
|
self.inject_allocator_dependency(cnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn inject_allocator_dependency(&self, allocator: ast::CrateNum) {
|
|
|
|
// Before we inject any dependencies, make sure we don't inject a
|
|
|
|
// circular dependency by validating that this allocator crate doesn't
|
|
|
|
// transitively depend on any `#![needs_allocator]` crates.
|
|
|
|
validate(self, allocator, allocator);
|
|
|
|
|
|
|
|
// All crates tagged with `needs_allocator` do not explicitly depend on
|
|
|
|
// the allocator selected for this compile, but in order for this
|
|
|
|
// compilation to be successfully linked we need to inject a dependency
|
|
|
|
// (to order the crates on the command line correctly).
|
|
|
|
//
|
|
|
|
// Here we inject a dependency from all crates with #![needs_allocator]
|
|
|
|
// to the crate tagged with #![allocator] for this compilation unit.
|
|
|
|
self.sess.cstore.iter_crate_data(|cnum, data| {
|
|
|
|
if !data.needs_allocator() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("injecting a dep from {} to {}", cnum, allocator);
|
|
|
|
let mut cnum_map = data.cnum_map.borrow_mut();
|
|
|
|
let remote_cnum = cnum_map.len() + 1;
|
|
|
|
let prev = cnum_map.insert(remote_cnum as ast::CrateNum, allocator);
|
|
|
|
assert!(prev.is_none());
|
|
|
|
});
|
|
|
|
|
|
|
|
fn validate(me: &CrateReader, krate: ast::CrateNum,
|
|
|
|
allocator: ast::CrateNum) {
|
|
|
|
let data = me.sess.cstore.get_crate_data(krate);
|
|
|
|
if data.needs_allocator() {
|
|
|
|
let krate_name = data.name();
|
|
|
|
let data = me.sess.cstore.get_crate_data(allocator);
|
|
|
|
let alloc_name = data.name();
|
|
|
|
me.sess.err(&format!("the allocator crate `{}` cannot depend \
|
|
|
|
on a crate that needs an allocator, but \
|
|
|
|
it depends on `{}`", alloc_name,
|
|
|
|
krate_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (_, &dep) in data.cnum_map.borrow().iter() {
|
|
|
|
validate(me, dep, allocator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-25 12:10:33 -06:00
|
|
|
}
|
2015-02-11 11:29:49 -06:00
|
|
|
|
2015-07-30 14:59:42 -05:00
|
|
|
impl<'a, 'b> LocalCrateReader<'a, 'b> {
|
2015-07-31 02:04:06 -05:00
|
|
|
pub fn new(sess: &'a Session, map: &'a hir_map::Map<'b>) -> LocalCrateReader<'a, 'b> {
|
2015-07-30 14:59:42 -05:00
|
|
|
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.
|
2015-07-31 02:04:06 -05:00
|
|
|
pub fn read_crates(&mut self, krate: &hir::Crate) {
|
2015-07-30 14:59:42 -05:00
|
|
|
self.process_crate(krate);
|
|
|
|
visit::walk_crate(self, krate);
|
2015-06-25 12:07:01 -05:00
|
|
|
self.creader.inject_allocator_crate();
|
2015-07-30 14:59:42 -05:00
|
|
|
|
2015-06-25 12:07:01 -05:00
|
|
|
if log_enabled!(log::INFO) {
|
2015-07-30 14:59:42 -05:00
|
|
|
dump_crates(&self.sess.cstore);
|
|
|
|
}
|
|
|
|
|
|
|
|
for &(ref name, kind) in &self.sess.opts.libs {
|
|
|
|
register_native_lib(self.sess, None, name.clone(), kind);
|
|
|
|
}
|
2015-07-30 16:20:36 -05:00
|
|
|
self.creader.register_statically_included_foreign_items();
|
2015-07-30 14:59:42 -05:00
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn process_crate(&self, c: &hir::Crate) {
|
2015-07-30 14:59:42 -05:00
|
|
|
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 */ }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn process_item(&mut self, i: &hir::Item) {
|
2015-07-30 14:59:42 -05:00
|
|
|
match i.node {
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ItemExternCrate(_) => {
|
|
|
|
if !should_link_hir(i) {
|
2015-07-30 14:59:42 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
match self.creader.extract_crate_info_hir(i) {
|
2015-07-30 14:59:42 -05:00
|
|
|
Some(info) => {
|
2015-08-01 09:14:45 -05:00
|
|
|
let (cnum, cmeta, _) = self.creader.resolve_crate(&None,
|
2015-07-30 14:59:42 -05:00
|
|
|
&info.ident,
|
|
|
|
&info.name,
|
|
|
|
None,
|
|
|
|
i.span,
|
2015-06-25 12:07:01 -05:00
|
|
|
PathKind::Crate,
|
|
|
|
true);
|
2015-09-17 13:29:59 -05:00
|
|
|
let def_id = self.ast_map.local_def_id(i.id);
|
|
|
|
let def_path = self.ast_map.def_path(def_id);
|
|
|
|
cmeta.update_local_def_path(def_path);
|
2015-07-30 16:20:36 -05:00
|
|
|
self.ast_map.with_path(i.id, |path| {
|
|
|
|
cmeta.update_local_path(path)
|
|
|
|
});
|
2015-07-30 14:59:42 -05:00
|
|
|
self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
|
|
|
|
}
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ItemForeignMod(ref fm) => self.process_foreign_mod(i, fm),
|
2015-07-30 16:20:36 -05:00
|
|
|
_ => { }
|
|
|
|
}
|
|
|
|
}
|
2015-07-30 14:59:42 -05:00
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn process_foreign_mod(&mut self, i: &hir::Item, fm: &hir::ForeignMod) {
|
2015-08-06 13:11:26 -05:00
|
|
|
if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic || fm.abi == abi::PlatformIntrinsic {
|
2015-07-30 16:20:36 -05:00
|
|
|
return;
|
|
|
|
}
|
2015-07-30 14:59:42 -05:00
|
|
|
|
2015-07-30 16:20:36 -05:00
|
|
|
// First, add all of the custom #[link_args] attributes
|
|
|
|
for m in i.attrs.iter().filter(|a| a.check_name("link_args")) {
|
|
|
|
if let Some(linkarg) = m.value_str() {
|
|
|
|
self.sess.cstore.add_used_link_args(&linkarg);
|
2015-07-30 14:59:42 -05:00
|
|
|
}
|
2015-07-30 16:20:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Next, process all of the #[link(..)]-style arguments
|
|
|
|
for m in i.attrs.iter().filter(|a| a.check_name("link")) {
|
|
|
|
let items = match m.meta_item_list() {
|
|
|
|
Some(item) => item,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
let kind = items.iter().find(|k| {
|
|
|
|
k.check_name("kind")
|
|
|
|
}).and_then(|a| a.value_str());
|
|
|
|
let kind = match kind.as_ref().map(|s| &s[..]) {
|
|
|
|
Some("static") => cstore::NativeStatic,
|
|
|
|
Some("dylib") => cstore::NativeUnknown,
|
|
|
|
Some("framework") => cstore::NativeFramework,
|
|
|
|
Some(k) => {
|
2015-09-11 09:17:15 -05:00
|
|
|
span_err!(self.sess, m.span, E0458,
|
|
|
|
"unknown kind: `{}`", k);
|
2015-07-30 16:20:36 -05:00
|
|
|
cstore::NativeUnknown
|
|
|
|
}
|
|
|
|
None => cstore::NativeUnknown
|
|
|
|
};
|
|
|
|
let n = items.iter().find(|n| {
|
|
|
|
n.check_name("name")
|
|
|
|
}).and_then(|a| a.value_str());
|
|
|
|
let n = match n {
|
|
|
|
Some(n) => n,
|
|
|
|
None => {
|
2015-09-11 09:17:15 -05:00
|
|
|
span_err!(self.sess, m.span, E0459,
|
|
|
|
"#[link(...)] specified without `name = \"foo\"`");
|
2015-07-30 16:20:36 -05:00
|
|
|
InternedString::new("foo")
|
|
|
|
}
|
|
|
|
};
|
|
|
|
register_native_lib(self.sess, Some(m.span), n.to_string(), kind);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, process the #[linked_from = "..."] attribute
|
|
|
|
for m in i.attrs.iter().filter(|a| a.check_name("linked_from")) {
|
|
|
|
let lib_name = match m.value_str() {
|
|
|
|
Some(name) => name,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
let list = self.creader.foreign_item_map.entry(lib_name.to_string())
|
|
|
|
.or_insert(Vec::new());
|
|
|
|
list.extend(fm.items.iter().map(|it| it.id));
|
2015-07-30 14:59:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-11 11:29:49 -06:00
|
|
|
/// Imports the codemap from an external crate into the codemap of the crate
|
|
|
|
/// currently being compiled (the "local crate").
|
|
|
|
///
|
|
|
|
/// The import algorithm works analogous to how AST items are inlined from an
|
|
|
|
/// external crate's metadata:
|
|
|
|
/// For every FileMap in the external codemap an 'inline' copy is created in the
|
|
|
|
/// local codemap. The correspondence relation between external and local
|
|
|
|
/// FileMaps is recorded in the `ImportedFileMap` objects returned from this
|
|
|
|
/// function. When an item from an external crate is later inlined into this
|
|
|
|
/// crate, this correspondence information is used to translate the span
|
|
|
|
/// information of the inlined item so that it refers the correct positions in
|
|
|
|
/// the local codemap (see `astencode::DecodeContext::tr_span()`).
|
|
|
|
///
|
|
|
|
/// The import algorithm in the function below will reuse FileMaps already
|
|
|
|
/// existing in the local codemap. For example, even if the FileMap of some
|
|
|
|
/// source file of libstd gets imported many times, there will only ever be
|
|
|
|
/// one FileMap object for the corresponding file in the local codemap.
|
|
|
|
///
|
|
|
|
/// Note that imported FileMaps do not actually contain the source code of the
|
|
|
|
/// file they represent, just information about length, line breaks, and
|
|
|
|
/// multibyte characters. This information is enough to generate valid debuginfo
|
|
|
|
/// for items inlined from other crates.
|
2015-05-22 08:15:21 -05:00
|
|
|
pub fn import_codemap(local_codemap: &codemap::CodeMap,
|
|
|
|
metadata: &MetadataBlob)
|
|
|
|
-> Vec<cstore::ImportedFileMap> {
|
2015-02-11 11:29:49 -06:00
|
|
|
let external_codemap = decoder::get_imported_filemaps(metadata.as_slice());
|
|
|
|
|
|
|
|
let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| {
|
|
|
|
// Try to find an existing FileMap that can be reused for the filemap to
|
|
|
|
// be imported. A FileMap is reusable if it is exactly the same, just
|
|
|
|
// positioned at a different offset within the codemap.
|
|
|
|
let reusable_filemap = {
|
|
|
|
local_codemap.files
|
|
|
|
.borrow()
|
|
|
|
.iter()
|
|
|
|
.find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import))
|
|
|
|
.map(|rc| rc.clone())
|
|
|
|
};
|
|
|
|
|
|
|
|
match reusable_filemap {
|
|
|
|
Some(fm) => {
|
|
|
|
cstore::ImportedFileMap {
|
|
|
|
original_start_pos: filemap_to_import.start_pos,
|
|
|
|
original_end_pos: filemap_to_import.end_pos,
|
|
|
|
translated_filemap: fm
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
// We can't reuse an existing FileMap, so allocate a new one
|
|
|
|
// containing the information we need.
|
|
|
|
let codemap::FileMap {
|
|
|
|
name,
|
|
|
|
start_pos,
|
|
|
|
end_pos,
|
|
|
|
lines,
|
|
|
|
multibyte_chars,
|
|
|
|
..
|
|
|
|
} = filemap_to_import;
|
|
|
|
|
|
|
|
let source_length = (end_pos - start_pos).to_usize();
|
|
|
|
|
|
|
|
// Translate line-start positions and multibyte character
|
|
|
|
// position into frame of reference local to file.
|
|
|
|
// `CodeMap::new_imported_filemap()` will then translate those
|
|
|
|
// coordinates to their new global frame of reference when the
|
|
|
|
// offset of the FileMap is known.
|
2015-07-08 10:33:13 -05:00
|
|
|
let mut lines = lines.into_inner();
|
|
|
|
for pos in &mut lines {
|
|
|
|
*pos = *pos - start_pos;
|
|
|
|
}
|
|
|
|
let mut multibyte_chars = multibyte_chars.into_inner();
|
|
|
|
for mbc in &mut multibyte_chars {
|
|
|
|
mbc.pos = mbc.pos - start_pos;
|
|
|
|
}
|
2015-02-11 11:29:49 -06:00
|
|
|
|
|
|
|
let local_version = local_codemap.new_imported_filemap(name,
|
|
|
|
source_length,
|
|
|
|
lines,
|
|
|
|
multibyte_chars);
|
|
|
|
cstore::ImportedFileMap {
|
|
|
|
original_start_pos: start_pos,
|
|
|
|
original_end_pos: end_pos,
|
|
|
|
translated_filemap: local_version
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
return imported_filemaps;
|
|
|
|
|
|
|
|
fn are_equal_modulo_startpos(fm1: &codemap::FileMap,
|
|
|
|
fm2: &codemap::FileMap)
|
|
|
|
-> bool {
|
|
|
|
if fm1.name != fm2.name {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let lines1 = fm1.lines.borrow();
|
|
|
|
let lines2 = fm2.lines.borrow();
|
|
|
|
|
|
|
|
if lines1.len() != lines2.len() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (&line1, &line2) in lines1.iter().zip(lines2.iter()) {
|
|
|
|
if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let multibytes1 = fm1.multibyte_chars.borrow();
|
|
|
|
let multibytes2 = fm2.multibyte_chars.borrow();
|
|
|
|
|
|
|
|
if multibytes1.len() != multibytes2.len() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) {
|
|
|
|
if (mb1.bytes != mb2.bytes) ||
|
|
|
|
((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|