From 0a8bb4c509e513a87a1bc0c04e0b7b8e13b82d2f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 25 Nov 2015 00:00:26 +0200 Subject: split the metadata code into rustc_metadata tests & rustdoc still broken --- src/librustc/diagnostics.rs | 60 - src/librustc/front/map/definitions.rs | 2 +- src/librustc/front/map/mod.rs | 4 +- src/librustc/lib.rs | 5 +- src/librustc/metadata/common.rs | 253 ---- src/librustc/metadata/creader.rs | 986 ------------ src/librustc/metadata/csearch.rs | 408 ----- src/librustc/metadata/cstore.rs | 368 ----- src/librustc/metadata/decoder.rs | 1567 ------------------- src/librustc/metadata/encoder.rs | 2078 -------------------------- src/librustc/metadata/filesearch.rs | 207 --- src/librustc/metadata/index.rs | 145 -- src/librustc/metadata/inline.rs | 60 - src/librustc/metadata/loader.rs | 852 ----------- src/librustc/metadata/macro_import.rs | 189 --- src/librustc/metadata/mod.rs | 23 - src/librustc/metadata/tydecode.rs | 711 --------- src/librustc/metadata/tyencode.rs | 479 ------ src/librustc/metadata/util.rs | 616 -------- src/librustc/middle/astencode.rs | 1464 ------------------ src/librustc/middle/const_eval.rs | 12 +- src/librustc/middle/cstore.rs | 277 ++++ src/librustc/middle/def_id.rs | 2 +- src/librustc/middle/dependency_format.rs | 4 +- src/librustc/middle/infer/error_reporting.rs | 2 +- src/librustc/middle/lang_items.rs | 2 +- src/librustc/middle/region.rs | 2 +- src/librustc/middle/stability.rs | 3 +- src/librustc/middle/traits/coherence.rs | 2 +- src/librustc/middle/ty/context.rs | 2 +- src/librustc/middle/ty/mod.rs | 3 +- src/librustc/middle/weak_lang_items.rs | 2 +- src/librustc/session/config.rs | 2 +- src/librustc/session/filesearch.rs | 207 +++ src/librustc/session/mod.rs | 4 +- src/librustc_driver/driver.rs | 8 +- src/librustc_driver/lib.rs | 9 +- src/librustc_driver/pretty.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/lib.rs | 1 - src/librustc_metadata/astencode.rs | 1472 ++++++++++++++++++ src/librustc_metadata/common.rs | 245 +++ src/librustc_metadata/creader.rs | 963 ++++++++++++ src/librustc_metadata/csearch.rs | 487 ++++++ src/librustc_metadata/cstore.rs | 345 +++++ src/librustc_metadata/decoder.rs | 1557 +++++++++++++++++++ src/librustc_metadata/diagnostics.rs | 77 + src/librustc_metadata/encoder.rs | 2078 ++++++++++++++++++++++++++ src/librustc_metadata/index.rs | 145 ++ src/librustc_metadata/lib.rs | 61 + src/librustc_metadata/loader.rs | 854 +++++++++++ src/librustc_metadata/macro_import.rs | 190 +++ src/librustc_metadata/macros.rs | 46 + src/librustc_metadata/tydecode.rs | 711 +++++++++ src/librustc_metadata/tyencode.rs | 479 ++++++ src/librustc_plugin/lib.rs | 1 + src/librustc_plugin/load.rs | 4 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_trans/back/archive.rs | 2 +- src/librustc_trans/back/link.rs | 9 +- src/librustc_trans/back/linker.rs | 2 +- src/librustc_trans/lib.rs | 1 - src/librustc_trans/save/recorder.rs | 2 +- src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/callee.rs | 2 +- src/librustc_trans/trans/consts.rs | 2 +- src/librustc_trans/trans/context.rs | 2 +- src/librustc_trans/trans/inline.rs | 2 +- src/librustc_trans/trans/mod.rs | 2 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 10 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/coherence/overlap.rs | 3 +- src/librustc_typeck/lib.rs | 1 - 76 files changed, 10256 insertions(+), 10536 deletions(-) delete mode 100644 src/librustc/metadata/common.rs delete mode 100644 src/librustc/metadata/creader.rs delete mode 100644 src/librustc/metadata/csearch.rs delete mode 100644 src/librustc/metadata/cstore.rs delete mode 100644 src/librustc/metadata/decoder.rs delete mode 100644 src/librustc/metadata/encoder.rs delete mode 100644 src/librustc/metadata/filesearch.rs delete mode 100644 src/librustc/metadata/index.rs delete mode 100644 src/librustc/metadata/inline.rs delete mode 100644 src/librustc/metadata/loader.rs delete mode 100644 src/librustc/metadata/macro_import.rs delete mode 100644 src/librustc/metadata/mod.rs delete mode 100644 src/librustc/metadata/tydecode.rs delete mode 100644 src/librustc/metadata/tyencode.rs delete mode 100644 src/librustc/metadata/util.rs delete mode 100644 src/librustc/middle/astencode.rs create mode 100644 src/librustc/middle/cstore.rs create mode 100644 src/librustc/session/filesearch.rs create mode 100644 src/librustc_metadata/astencode.rs create mode 100644 src/librustc_metadata/common.rs create mode 100644 src/librustc_metadata/creader.rs create mode 100644 src/librustc_metadata/csearch.rs create mode 100644 src/librustc_metadata/cstore.rs create mode 100644 src/librustc_metadata/decoder.rs create mode 100644 src/librustc_metadata/diagnostics.rs create mode 100644 src/librustc_metadata/encoder.rs create mode 100644 src/librustc_metadata/index.rs create mode 100644 src/librustc_metadata/lib.rs create mode 100644 src/librustc_metadata/loader.rs create mode 100644 src/librustc_metadata/macro_import.rs create mode 100644 src/librustc_metadata/macros.rs create mode 100644 src/librustc_metadata/tydecode.rs create mode 100644 src/librustc_metadata/tyencode.rs (limited to 'src') diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index a088567b419..b4e188c498d 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1899,51 +1899,6 @@ contain references (with a maximum lifetime of `'a`). [1]: https://github.com/rust-lang/rfcs/pull/1156 "##, -E0454: r##" -A link name was given with an empty name. Erroneous code example: - -``` -#[link(name = "")] extern {} // error: #[link(name = "")] given with empty name -``` - -The rust compiler cannot link to an external library if you don't give it its -name. Example: - -``` -#[link(name = "some_lib")] extern {} // ok! -``` -"##, - -E0458: r##" -An unknown "kind" was specified for a link attribute. Erroneous code example: - -``` -#[link(kind = "wonderful_unicorn")] extern {} -// error: unknown kind: `wonderful_unicorn` -``` - -Please specify a valid "kind" value, from one of the following: - * static - * dylib - * framework -"##, - -E0459: r##" -A link was used without a name parameter. Erroneous code example: - -``` -#[link(kind = "dylib")] extern {} -// error: #[link(...)] specified without `name = "foo"` -``` - -Please add the name parameter to allow the rust compiler to find the library -you want. Example: - -``` -#[link(kind = "dylib", name = "some_lib")] extern {} // ok! -``` -"##, - E0493: r##" A type with a destructor was assigned to an invalid type of variable. Erroneous code example: @@ -2144,20 +2099,6 @@ register_diagnostics! { E0400, // overloaded derefs are not allowed in constants E0452, // malformed lint attribute E0453, // overruled by outer forbid - E0455, // native frameworks are only available on OSX targets - E0456, // plugin `..` is not available for triple `..` - E0457, // plugin `..` only found in rlib format, but must be available... - E0460, // found possibly newer version of crate `..` - E0461, // couldn't find crate `..` with expected target triple .. - E0462, // found staticlib `..` instead of rlib or dylib - E0463, // can't find crate for `..` - E0464, // multiple matching crates for `..` - E0465, // multiple .. candidates for `..` found - E0466, // bad macro import - E0467, // bad macro reexport - E0468, // an `extern crate` loading macros must be at the crate root - E0469, // imported macro not found - E0470, // reexported macro not found E0471, // constant evaluation error: .. E0472, // asm! is unsupported on this target E0473, // dereference of reference outside its lifetime @@ -2181,5 +2122,4 @@ register_diagnostics! { E0491, // in type `..`, reference has a longer lifetime than the data it... E0492, // cannot borrow a constant which contains interior mutability E0495, // cannot infer an appropriate lifetime due to conflicting requirements - E0514, // metadata version mismatch } diff --git a/src/librustc/front/map/definitions.rs b/src/librustc/front/map/definitions.rs index c1eb5f1f118..0f0d59e70b0 100644 --- a/src/librustc/front/map/definitions.rs +++ b/src/librustc/front/map/definitions.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use metadata::cstore::LOCAL_CRATE; +use middle::cstore::LOCAL_CRATE; use middle::def_id::{DefId, DefIndex}; use rustc_data_structures::fnv::FnvHashMap; use rustc_front::hir; diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs index 6ee6b070597..8c3da2cddd5 100644 --- a/src/librustc/front/map/mod.rs +++ b/src/librustc/front/map/mod.rs @@ -14,8 +14,8 @@ use self::MapEntry::*; use self::collector::NodeCollector; pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; -use metadata::inline::InlinedItem; -use metadata::inline::InlinedItem as II; +use middle::cstore::InlinedItem; +use middle::cstore::InlinedItem as II; use middle::def_id::DefId; use syntax::abi; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 62646f6bc56..6da4f174e3e 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -67,7 +67,6 @@ extern crate rustc_back; extern crate rustc_front; extern crate rustc_data_structures; extern crate serialize; -extern crate rbml; extern crate collections; #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -101,7 +100,6 @@ pub mod front { pub mod middle { pub mod astconv_util; pub mod expr_use_visitor; // STAGE0: increase glitch immunity - pub mod astencode; pub mod cfg; pub mod check_const; pub mod check_static_recursion; @@ -110,6 +108,7 @@ pub mod middle { pub mod check_no_asm; pub mod check_rvalues; pub mod const_eval; + pub mod cstore; pub mod dataflow; pub mod dead; pub mod def; @@ -137,8 +136,6 @@ pub mod middle { pub mod weak_lang_items; } -pub mod metadata; - pub mod session; pub mod lint; diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs deleted file mode 100644 index a4fee5b7aa8..00000000000 --- a/src/librustc/metadata/common.rs +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types, non_upper_case_globals)] - -pub use self::astencode_tag::*; - -use back::svh::Svh; - -// RBML enum definitions and utils shared by the encoder and decoder -// -// 0x00..0x1f: reserved for RBML generic type tags -// 0x20..0xef: free for use, preferred for frequent tags -// 0xf0..0xff: internally used by RBML to encode 0x100..0xfff in two bytes -// 0x100..0xfff: free for use, preferred for infrequent tags - -pub const tag_items: usize = 0x100; // top-level only - -pub const tag_paths_data_name: usize = 0x20; - -pub const tag_def_id: usize = 0x21; - -pub const tag_items_data: usize = 0x22; - -pub const tag_items_data_item: usize = 0x23; - -pub const tag_items_data_item_family: usize = 0x24; - -pub const tag_items_data_item_type: usize = 0x25; - -pub const tag_items_data_item_symbol: usize = 0x26; - -pub const tag_items_data_item_variant: usize = 0x27; - -pub const tag_items_data_parent_item: usize = 0x28; - -pub const tag_items_data_item_is_tuple_struct_ctor: usize = 0x29; - -pub const tag_items_closure_kind: usize = 0x2a; -pub const tag_items_closure_ty: usize = 0x2b; -pub const tag_def_key: usize = 0x2c; - -// GAP 0x2d 0x2e - -pub const tag_index: usize = 0x110; // top-level only -pub const tag_xref_index: usize = 0x111; // top-level only -pub const tag_xref_data: usize = 0x112; // top-level only - -pub const tag_meta_item_name_value: usize = 0x2f; - -pub const tag_meta_item_name: usize = 0x30; - -pub const tag_meta_item_value: usize = 0x31; - -pub const tag_attributes: usize = 0x101; // top-level only - -pub const tag_attribute: usize = 0x32; - -pub const tag_meta_item_word: usize = 0x33; - -pub const tag_meta_item_list: usize = 0x34; - -// The list of crates that this crate depends on -pub const tag_crate_deps: usize = 0x102; // top-level only - -// A single crate dependency -pub const tag_crate_dep: usize = 0x35; - -pub const tag_crate_hash: usize = 0x103; // top-level only -pub const tag_crate_crate_name: usize = 0x104; // top-level only - -pub const tag_crate_dep_crate_name: usize = 0x36; -pub const tag_crate_dep_hash: usize = 0x37; -pub const tag_crate_dep_explicitly_linked: usize = 0x38; // top-level only - -pub const tag_item_trait_item: usize = 0x3a; - -pub const tag_item_trait_ref: usize = 0x3b; - -// discriminator value for variants -pub const tag_disr_val: usize = 0x3c; - -// used to encode ast_map::PathElem -pub const tag_path: usize = 0x3d; -pub const tag_path_len: usize = 0x3e; -pub const tag_path_elem_mod: usize = 0x3f; -pub const tag_path_elem_name: usize = 0x40; -pub const tag_item_field: usize = 0x41; - -pub const tag_item_variances: usize = 0x43; -/* - trait items contain tag_item_trait_item elements, - impl items contain tag_item_impl_item elements, and classes - have both. That's because some code treats classes like traits, - and other code treats them like impls. Because classes can contain - both, tag_item_trait_item and tag_item_impl_item have to be two - different tags. - */ -pub const tag_item_impl_item: usize = 0x44; -pub const tag_item_trait_method_explicit_self: usize = 0x45; - - -// Reexports are found within module tags. Each reexport contains def_ids -// and names. -pub const tag_items_data_item_reexport: usize = 0x46; -pub const tag_items_data_item_reexport_def_id: usize = 0x47; -pub const tag_items_data_item_reexport_name: usize = 0x48; - -// used to encode crate_ctxt side tables -enum_from_u32! { - #[derive(Copy, Clone, PartialEq)] - #[repr(usize)] - pub enum astencode_tag { // Reserves 0x50 -- 0x6f - tag_ast = 0x50, - - tag_tree = 0x51, - - // GAP 0x52 - tag_table = 0x53, - // GAP 0x54, 0x55 - tag_table_def = 0x56, - tag_table_node_type = 0x57, - tag_table_item_subst = 0x58, - tag_table_freevars = 0x59, - // GAP 0x5a, 0x5b, 0x5c, 0x5d, 0x5e - tag_table_method_map = 0x5f, - // GAP 0x60 - tag_table_adjustments = 0x61, - // GAP 0x62, 0x63, 0x64, 0x65 - tag_table_upvar_capture_map = 0x66, - // GAP 0x67, 0x68 - tag_table_const_qualif = 0x69, - tag_table_cast_kinds = 0x6a, - } -} - -pub const tag_item_trait_item_sort: usize = 0x70; - -pub const tag_crate_triple: usize = 0x105; // top-level only - -pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only - -// Language items are a top-level directory (for speed). Hierarchy: -// -// tag_lang_items -// - tag_lang_items_item -// - tag_lang_items_item_id: u32 -// - tag_lang_items_item_index: u32 - -pub const tag_lang_items: usize = 0x107; // top-level only -pub const tag_lang_items_item: usize = 0x73; -pub const tag_lang_items_item_id: usize = 0x74; -pub const tag_lang_items_item_index: usize = 0x75; -pub const tag_lang_items_missing: usize = 0x76; - -pub const tag_item_unnamed_field: usize = 0x77; -pub const tag_items_data_item_visibility: usize = 0x78; -pub const tag_items_data_item_inherent_impl: usize = 0x79; -// GAP 0x7a -pub const tag_mod_child: usize = 0x7b; -pub const tag_misc_info: usize = 0x108; // top-level only -pub const tag_misc_info_crate_items: usize = 0x7c; - -pub const tag_impls: usize = 0x109; // top-level only -pub const tag_impls_trait: usize = 0x7d; -pub const tag_impls_trait_impl: usize = 0x7e; - -// GAP 0x7f, 0x80, 0x81 - -pub const tag_native_libraries: usize = 0x10a; // top-level only -pub const tag_native_libraries_lib: usize = 0x82; -pub const tag_native_libraries_name: usize = 0x83; -pub const tag_native_libraries_kind: usize = 0x84; - -pub const tag_plugin_registrar_fn: usize = 0x10b; // top-level only - -pub const tag_method_argument_names: usize = 0x85; -pub const tag_method_argument_name: usize = 0x86; - -pub const tag_reachable_ids: usize = 0x10c; // top-level only -pub const tag_reachable_id: usize = 0x87; - -pub const tag_items_data_item_stability: usize = 0x88; - -pub const tag_items_data_item_repr: usize = 0x89; - -#[derive(Clone, Debug)] -pub struct LinkMeta { - pub crate_name: String, - pub crate_hash: Svh, -} - -pub const tag_struct_fields: usize = 0x10d; // top-level only -pub const tag_struct_field: usize = 0x8a; - -pub const tag_items_data_item_struct_ctor: usize = 0x8b; -pub const tag_attribute_is_sugared_doc: usize = 0x8c; -// GAP 0x8d -pub const tag_items_data_region: usize = 0x8e; - -pub const tag_region_param_def: usize = 0x8f; -pub const tag_region_param_def_ident: usize = 0x90; -pub const tag_region_param_def_def_id: usize = 0x91; -pub const tag_region_param_def_space: usize = 0x92; -pub const tag_region_param_def_index: usize = 0x93; - -pub const tag_type_param_def: usize = 0x94; - -pub const tag_item_generics: usize = 0x95; -pub const tag_method_ty_generics: usize = 0x96; - -pub const tag_type_predicate: usize = 0x97; -pub const tag_self_predicate: usize = 0x98; -pub const tag_fn_predicate: usize = 0x99; - -pub const tag_unsafety: usize = 0x9a; - -pub const tag_associated_type_names: usize = 0x9b; -pub const tag_associated_type_name: usize = 0x9c; - -pub const tag_polarity: usize = 0x9d; - -pub const tag_macro_defs: usize = 0x10e; // top-level only -pub const tag_macro_def: usize = 0x9e; -pub const tag_macro_def_body: usize = 0x9f; - -pub const tag_paren_sugar: usize = 0xa0; - -pub const tag_codemap: usize = 0xa1; -pub const tag_codemap_filemap: usize = 0xa2; - -pub const tag_item_super_predicates: usize = 0xa3; - -pub const tag_defaulted_trait: usize = 0xa4; - -pub const tag_impl_coerce_unsized_kind: usize = 0xa5; - -pub const tag_items_data_item_constness: usize = 0xa6; - -pub const tag_rustc_version: usize = 0x10f; -pub fn rustc_version() -> String { - format!( - "rustc {}", - option_env!("CFG_VERSION").unwrap_or("unknown version") - ) -} diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs deleted file mode 100644 index 191b1705371..00000000000 --- a/src/librustc/metadata/creader.rs +++ /dev/null @@ -1,986 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types)] - -//! Validates all used crates and extern libraries and loads their metadata - -use back::svh::Svh; -use session::{config, Session}; -use session::search_paths::PathKind; -use metadata::common::rustc_version; -use metadata::cstore; -use metadata::cstore::{CStore, CrateSource, MetadataBlob}; -use metadata::decoder; -use metadata::loader; -use metadata::loader::CratePaths; -use util::nodemap::FnvHashMap; -use front::map as hir_map; - -use std::cell::{RefCell, Cell}; -use std::path::PathBuf; -use std::rc::Rc; -use std::fs; - -use syntax::ast; -use syntax::abi; -use syntax::codemap::{self, Span, mk_sp, Pos}; -use syntax::parse; -use syntax::attr; -use syntax::attr::AttrMetaMethods; -use syntax::parse::token::InternedString; -use syntax::util::small_vector::SmallVector; -use rustc_front::intravisit::Visitor; -use rustc_front::hir; -use log; - -pub struct LocalCrateReader<'a, 'b:'a> { - sess: &'a Session, - cstore: &'a CStore, - creader: CrateReader<'a>, - ast_map: &'a hir_map::Map<'b>, -} - -pub struct CrateReader<'a> { - sess: &'a Session, - cstore: &'a CStore, - next_crate_num: ast::CrateNum, - foreign_item_map: FnvHashMap>, -} - -impl<'a, 'b, 'hir> Visitor<'hir> for LocalCrateReader<'a, 'b> { - fn visit_item(&mut self, a: &'hir hir::Item) { - self.process_item(a); - } -} - -fn dump_crates(cstore: &CStore) { - info!("resolved crates:"); - cstore.iter_crate_data_origins(|_, data, opt_source| { - info!(" name: {}", data.name()); - info!(" cnum: {}", data.cnum); - info!(" hash: {}", data.hash()); - info!(" reqd: {}", data.explicitly_linked.get()); - opt_source.map(|cs| { - let CrateSource { dylib, rlib, cnum: _ } = cs; - dylib.map(|dl| info!(" dylib: {}", dl.0.display())); - rlib.map(|rl| info!(" rlib: {}", rl.0.display())); - }); - }) -} - -fn should_link(i: &ast::Item) -> bool { - !attr::contains_name(&i.attrs, "no_link") -} -// Dup for the hir -fn should_link_hir(i: &hir::Item) -> bool { - !attr::contains_name(&i.attrs, "no_link") -} - -struct CrateInfo { - ident: String, - name: String, - id: ast::NodeId, - should_link: bool, -} - -pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { - let say = |s: &str| { - match (sp, sess) { - (_, None) => panic!("{}", s), - (Some(sp), Some(sess)) => sess.span_err(sp, s), - (None, Some(sess)) => sess.err(s), - } - }; - if s.is_empty() { - say("crate name must not be empty"); - } - for c in s.chars() { - if c.is_alphanumeric() { continue } - if c == '_' { continue } - say(&format!("invalid character `{}` in crate name: `{}`", c, s)); - } - match sess { - Some(sess) => sess.abort_if_errors(), - None => {} - } -} - - -fn register_native_lib(sess: &Session, - cstore: &CStore, - span: Option, - name: String, - kind: cstore::NativeLibraryKind) { - if name.is_empty() { - match span { - Some(span) => { - span_err!(sess, span, E0454, - "#[link(name = \"\")] given with empty name"); - } - None => { - sess.err("empty library name given via `-l`"); - } - } - return - } - let is_osx = sess.target.target.options.is_like_osx; - if kind == cstore::NativeFramework && !is_osx { - let msg = "native frameworks are only available on OSX targets"; - match span { - Some(span) => { - span_err!(sess, span, E0455, - "{}", msg) - } - None => sess.err(msg), - } - } - cstore.add_used_library(name, kind); -} - -// Extra info about a crate loaded for plugins or exported macros. -struct ExtensionCrate { - metadata: PMDSource, - dylib: Option, - target_only: bool, -} - -enum PMDSource { - Registered(Rc), - 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(), - } - } -} - -impl<'a> CrateReader<'a> { - pub fn new(sess: &'a Session, cstore: &'a CStore) -> CrateReader<'a> { - CrateReader { - sess: sess, - cstore: cstore, - next_crate_num: cstore.next_crate_num(), - foreign_item_map: FnvHashMap(), - } - } - - fn extract_crate_info(&self, i: &ast::Item) -> Option { - match i.node { - ast::ItemExternCrate(ref path_opt) => { - debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", - i.ident, path_opt); - let name = match *path_opt { - Some(name) => { - validate_crate_name(Some(self.sess), &name.as_str(), - Some(i.span)); - name.to_string() - } - None => i.ident.to_string(), - }; - Some(CrateInfo { - ident: i.ident.to_string(), - name: name, - id: i.id, - should_link: should_link(i), - }) - } - _ => None - } - } - - // Dup of the above, but for the hir - fn extract_crate_info_hir(&self, i: &hir::Item) -> Option { - match i.node { - hir::ItemExternCrate(ref path_opt) => { - debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", - i.name, path_opt); - let name = match *path_opt { - Some(name) => { - validate_crate_name(Some(self.sess), &name.as_str(), - Some(i.span)); - name.to_string() - } - None => i.name.to_string(), - }; - Some(CrateInfo { - ident: i.name.to_string(), - name: name, - id: i.id, - should_link: should_link_hir(i), - }) - } - _ => None - } - } - - fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind) - -> Option { - let mut ret = None; - self.cstore.iter_crate_data(|cnum, data| { - if data.name != name { return } - - match hash { - Some(hash) if *hash == data.hash() => { ret = Some(cnum); return } - Some(..) => return, - None => {} - } - - // 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. - // - // 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.cstore.do_get_used_crate_source(cnum).unwrap(); - if let Some(locs) = self.sess.opts.externs.get(name) { - let found = locs.iter().any(|l| { - let l = fs::canonicalize(l).ok(); - 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); - } - return - } - - // 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); - } - }); - return ret; - } - - 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(); - } - } - - fn register_crate(&mut self, - root: &Option, - ident: &str, - name: &str, - span: Span, - lib: loader::Library, - explicitly_linked: bool) - -> (ast::CrateNum, Rc, - cstore::CrateSource) { - self.verify_rustc_version(name, span, &lib.metadata); - - // 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(), - dylib: lib.dylib.clone().map(|p| p.0), - rlib: lib.rlib.clone().map(|p| p.0), - }) - } else { - None - }; - // Maintain a reference to the top most crate. - let root = if root.is_some() { root } else { &crate_paths }; - - let loader::Library { dylib, rlib, metadata } = lib; - - let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span); - let staged_api = self.is_staged_api(metadata.as_slice()); - - let cmeta = Rc::new(cstore::crate_metadata { - name: name.to_string(), - local_path: RefCell::new(SmallVector::zero()), - local_def_path: RefCell::new(vec![]), - index: decoder::load_index(metadata.as_slice()), - xref_index: decoder::load_xrefs(metadata.as_slice()), - data: metadata, - cnum_map: RefCell::new(cnum_map), - cnum: cnum, - codemap_import_info: RefCell::new(vec![]), - span: span, - staged_api: staged_api, - explicitly_linked: Cell::new(explicitly_linked), - }); - - let source = cstore::CrateSource { - dylib: dylib, - rlib: rlib, - cnum: cnum, - }; - - self.cstore.set_crate_data(cnum, cmeta.clone()); - self.cstore.add_used_crate_source(source.clone()); - (cnum, cmeta, source) - } - - fn is_staged_api(&self, data: &[u8]) -> bool { - let attrs = decoder::get_crate_attributes(data); - for attr in &attrs { - if attr.name() == "stable" || attr.name() == "unstable" { - return true - } - } - false - } - - fn resolve_crate(&mut self, - root: &Option, - ident: &str, - name: &str, - hash: Option<&Svh>, - span: Span, - kind: PathKind, - explicitly_linked: bool) - -> (ast::CrateNum, Rc, - cstore::CrateSource) { - enum LookupResult { - Previous(ast::CrateNum), - Loaded(loader::Library), - } - let result = match self.existing_match(name, hash, kind) { - Some(cnum) => LookupResult::Previous(cnum), - 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), - target: &self.sess.target.target, - triple: &self.sess.opts.target_triple, - root: root, - rejected_via_hash: vec!(), - rejected_via_triple: vec!(), - rejected_via_kind: vec!(), - should_match_name: true, - }; - let library = load_ctxt.load_library_crate(); - - // In the case that we're loading a crate, but not matching - // against a hash, we could load a crate which has the same hash - // as an already loaded crate. If this is the case prevent - // duplicates by just using the first crate. - let meta_hash = decoder::get_crate_hash(library.metadata - .as_slice()); - let mut result = LookupResult::Loaded(library); - self.cstore.iter_crate_data(|cnum, data| { - if data.name() == name && meta_hash == data.hash() { - assert!(hash.is_none()); - result = LookupResult::Previous(cnum); - } - }); - result - } - }; - - match result { - LookupResult::Previous(cnum) => { - let data = self.cstore.get_crate_data(cnum); - if explicitly_linked && !data.explicitly_linked.get() { - data.explicitly_linked.set(explicitly_linked); - } - (cnum, data, self.cstore.do_get_used_crate_source(cnum).unwrap()) - } - LookupResult::Loaded(library) => { - self.register_crate(root, ident, name, span, library, - explicitly_linked) - } - } - } - - // Go through the crate metadata and load any crates that it references - fn resolve_crate_deps(&mut self, - root: &Option, - 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, - &dep.name, - &dep.name, - Some(&dep.hash), - span, - PathKind::Dependency, - dep.explicitly_linked); - (dep.cnum, local_cnum) - }).collect() - } - - fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { - let target_triple = &self.sess.opts.target_triple[..]; - let is_cross = target_triple != config::host_triple(); - let mut should_link = info.should_link && !is_cross; - let mut target_only = false; - let ident = info.ident.clone(); - let name = info.name.clone(); - let mut load_ctxt = loader::Context { - sess: self.sess, - span: span, - ident: &ident[..], - crate_name: &name[..], - hash: None, - filesearch: self.sess.host_filesearch(PathKind::Crate), - target: &self.sess.host, - triple: config::host_triple(), - root: &None, - rejected_via_hash: vec!(), - rejected_via_triple: vec!(), - rejected_via_kind: vec!(), - should_match_name: true, - }; - let library = match load_ctxt.maybe_load_library_crate() { - Some(l) => l, - None if is_cross => { - // Try loading from target crates. This will abort later if we - // try to load a plugin registrar function, - target_only = true; - should_link = info.should_link; - - load_ctxt.target = &self.sess.target.target; - load_ctxt.triple = target_triple; - load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate); - load_ctxt.load_library_crate() - } - None => { load_ctxt.report_load_errs(); unreachable!() }, - }; - - let dylib = library.dylib.clone(); - let register = should_link && self.existing_match(&info.name, - None, - PathKind::Crate).is_none(); - let metadata = if register { - // Register crate now to avoid double-reading metadata - let (_, cmd, _) = self.register_crate(&None, &info.ident, - &info.name, span, library, - true); - PMDSource::Registered(cmd) - } else { - // Not registering the crate; just hold on to the metadata - PMDSource::Owned(library.metadata) - }; - - ExtensionCrate { - metadata: metadata, - dylib: dylib.map(|p| p.0), - target_only: target_only, - } - } - - /// Read exported macros. - pub fn read_exported_macros(&mut self, item: &ast::Item) -> Vec { - let ci = self.extract_crate_info(item).unwrap(); - let ekrate = self.read_extension_crate(item.span, &ci); - - let source_name = format!("<{} macros>", item.ident); - let mut macros = vec![]; - decoder::each_exported_macro(ekrate.metadata.as_slice(), - &*self.cstore.intr, - |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; - let body = match p.parse_all_token_trees() { - Ok(body) => body, - Err(err) => panic!(err), - }; - let span = mk_sp(lo, p.last_span.hi); - p.abort_if_errors(); - - // Mark the attrs as used - for attr in &attrs { - attr::mark_used(attr); - } - - macros.push(ast::MacroDef { - ident: ast::Ident::with_empty_ctxt(name), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - span: span, - imported_from: Some(item.ident), - // overridden in plugin/load.rs - export: false, - use_locally: false, - allow_internal_unstable: false, - - body: body, - }); - true - } - ); - macros - } - - /// Look for a plugin registrar. Returns library path and symbol name. - pub fn find_plugin_registrar(&mut self, span: Span, name: &str) - -> Option<(PathBuf, String)> { - 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 { - // Need to abort before syntax expansion. - let message = format!("plugin `{}` is not available for triple `{}` \ - (only found {})", - name, - config::host_triple(), - self.sess.opts.target_triple); - span_err!(self.sess, span, E0456, "{}", &message[..]); - self.sess.abort_if_errors(); - } - - let registrar = - decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()) - .map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id)); - - match (ekrate.dylib.as_ref(), registrar) { - (Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)), - (None, Some(_)) => { - span_err!(self.sess, span, E0457, - "plugin `{}` only found in rlib format, but must be available \ - in dylib format", - name); - // No need to abort because the loading code will just ignore this - // empty dylib. - None - } - _ => None, - } - } - - fn register_statically_included_foreign_items(&mut self) { - let libs = self.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.cstore.add_statically_included_foreign_item(*id); - } - } - } - } - - 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.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.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.cstore.get_crate_data(krate); - if data.needs_allocator() { - let krate_name = data.name(); - let data = me.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); - } - } - } -} - -impl<'a, 'b> LocalCrateReader<'a, 'b> { - pub fn new(sess: &'a Session, cstore: &'a CStore, map: &'a hir_map::Map<'b>) -> LocalCrateReader<'a, 'b> { - LocalCrateReader { - sess: sess, - cstore: cstore, - creader: CrateReader::new(sess, cstore), - 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: &hir::Crate) { - self.process_crate(krate); - krate.visit_all_items(self); - self.creader.inject_allocator_crate(); - - if log_enabled!(log::INFO) { - dump_crates(&self.cstore); - } - - for &(ref name, kind) in &self.sess.opts.libs { - register_native_lib(self.sess, self.cstore, None, name.clone(), kind); - } - self.creader.register_statically_included_foreign_items(); - } - - fn process_crate(&self, c: &hir::Crate) { - for a in c.attrs.iter().filter(|m| m.name() == "link_args") { - match a.value_str() { - Some(ref linkarg) => self.cstore.add_used_link_args(&linkarg), - None => { /* fallthrough */ } - } - } - } - - fn process_item(&mut self, i: &hir::Item) { - match i.node { - hir::ItemExternCrate(_) => { - if !should_link_hir(i) { - return; - } - - match self.creader.extract_crate_info_hir(i) { - Some(info) => { - let (cnum, cmeta, _) = self.creader.resolve_crate(&None, - &info.ident, - &info.name, - None, - i.span, - PathKind::Crate, - true); - 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); - self.ast_map.with_path(i.id, |path| { - cmeta.update_local_path(path) - }); - self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); - } - None => () - } - } - hir::ItemForeignMod(ref fm) => self.process_foreign_mod(i, fm), - _ => { } - } - } - - fn process_foreign_mod(&mut self, i: &hir::Item, fm: &hir::ForeignMod) { - if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic || fm.abi == abi::PlatformIntrinsic { - return; - } - - // 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.cstore.add_used_link_args(&linkarg); - } - } - - // 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) => { - span_err!(self.sess, m.span, E0458, - "unknown kind: `{}`", k); - 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 => { - span_err!(self.sess, m.span, E0459, - "#[link(...)] specified without `name = \"foo\"`"); - InternedString::new("foo") - } - }; - register_native_lib(self.sess, self.cstore, 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)); - } - } -} - -/// 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. -pub fn import_codemap(local_codemap: &codemap::CodeMap, - metadata: &MetadataBlob) - -> Vec { - 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. - 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; - } - - 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 - } -} diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs deleted file mode 100644 index 40159b24fe7..00000000000 --- a/src/librustc/metadata/csearch.rs +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Searching for information from the cstore - -use front::map as ast_map; -use metadata::cstore; -use metadata::decoder; -use metadata::inline::InlinedItem; -use middle::def_id::{DefId, DefIndex}; -use middle::lang_items; -use middle::ty; -use util::nodemap::FnvHashMap; - -use std::rc::Rc; -use syntax::ast; -use syntax::attr; -use rustc_front::hir; - -#[derive(Copy, Clone)] -pub struct MethodInfo { - pub name: ast::Name, - pub def_id: DefId, - pub vis: hir::Visibility, -} - -pub fn get_symbol(cstore: &cstore::CStore, def: DefId) -> String { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_symbol(&cdata, def.index) -} - -/// Iterates over all the language items in the given crate. -pub fn each_lang_item(cstore: &cstore::CStore, - cnum: ast::CrateNum, - f: F) - -> bool where - F: FnMut(DefIndex, usize) -> bool, -{ - let crate_data = cstore.get_crate_data(cnum); - decoder::each_lang_item(&*crate_data, f) -} - -/// Iterates over each child of the given item. -pub fn each_child_of_item(cstore: &cstore::CStore, - def_id: DefId, - callback: F) where - F: FnMut(decoder::DefLike, ast::Name, hir::Visibility), -{ - let crate_data = cstore.get_crate_data(def_id.krate); - let get_crate_data = |cnum| { - cstore.get_crate_data(cnum) - }; - decoder::each_child_of_item(cstore.intr.clone(), - &*crate_data, - def_id.index, - get_crate_data, - callback) -} - -/// Iterates over each top-level crate item. -pub fn each_top_level_item_of_crate(cstore: &cstore::CStore, - cnum: ast::CrateNum, - callback: F) where - F: FnMut(decoder::DefLike, ast::Name, hir::Visibility), -{ - let crate_data = cstore.get_crate_data(cnum); - let get_crate_data = |cnum| { - cstore.get_crate_data(cnum) - }; - decoder::each_top_level_item_of_crate(cstore.intr.clone(), - &*crate_data, - get_crate_data, - callback) -} - -pub fn get_item_path(tcx: &ty::ctxt, def: DefId) -> Vec { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - let path = decoder::get_item_path(&*cdata, def.index); - - 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 fn get_item_name(tcx: &ty::ctxt, def: DefId) -> ast::Name { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_item_name(&cstore.intr, &cdata, def.index) -} - -pub enum FoundAst<'ast> { - Found(&'ast InlinedItem), - FoundParent(DefId, &'ast InlinedItem), - NotFound, -} - -// Finds the AST for this item in the crate metadata, if any. If the item was -// not marked for inlining, then the AST will not be present and hence none -// will be returned. -pub fn maybe_get_item_ast<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId, - decode_inlined_item: decoder::DecodeInlinedItem) - -> FoundAst<'tcx> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::maybe_get_item_ast(&*cdata, tcx, def.index, decode_inlined_item) -} - -/// Returns information about the given implementation. -pub fn get_impl_items(cstore: &cstore::CStore, impl_def_id: DefId) - -> Vec { - let cdata = cstore.get_crate_data(impl_def_id.krate); - decoder::get_impl_items(&*cdata, impl_def_id.index) -} - -pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::ImplOrTraitItem<'tcx> { - let cdata = tcx.sess.cstore.get_crate_data(def.krate); - decoder::get_impl_or_trait_item(tcx.sess.cstore.intr.clone(), - &*cdata, - def.index, - tcx) -} - -pub fn get_trait_name(cstore: &cstore::CStore, def: DefId) -> ast::Name { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_trait_name(cstore.intr.clone(), - &*cdata, - def.index) -} - -pub fn is_static_method(cstore: &cstore::CStore, def: DefId) -> bool { - let cdata = cstore.get_crate_data(def.krate); - decoder::is_static_method(&*cdata, def.index) -} - -pub fn get_trait_item_def_ids(cstore: &cstore::CStore, def: DefId) - -> Vec { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_trait_item_def_ids(&*cdata, def.index) -} - -pub fn get_item_variances(cstore: &cstore::CStore, - def: DefId) -> ty::ItemVariances { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_item_variances(&*cdata, def.index) -} - -pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>, - def: DefId) - -> Vec>> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.index, tcx) -} - -pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) - -> Vec>> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.index, tcx) -} - -pub fn get_methods_if_impl(cstore: &cstore::CStore, - def: DefId) - -> Option > { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_methods_if_impl(cstore.intr.clone(), &*cdata, def.index) -} - -pub fn get_item_attrs(cstore: &cstore::CStore, - def_id: DefId) - -> Vec { - let cdata = cstore.get_crate_data(def_id.krate); - decoder::get_item_attrs(&*cdata, def_id.index) -} - -pub fn get_struct_field_names(cstore: &cstore::CStore, def: DefId) -> Vec { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_struct_field_names(&cstore.intr, &*cdata, def.index) -} - -pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: DefId) - -> FnvHashMap> { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_struct_field_attrs(&*cdata) -} - -pub fn get_type<'tcx>(tcx: &ty::ctxt<'tcx>, - def: DefId) - -> ty::TypeScheme<'tcx> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_type(&*cdata, def.index, tcx) -} - -pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::TraitDef<'tcx> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_trait_def(&*cdata, def.index, tcx) -} - -pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_adt_def(&cstore.intr, &*cdata, def.index, tcx) -} - -pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::GenericPredicates<'tcx> -{ - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_predicates(&*cdata, def.index, tcx) -} - -pub fn get_super_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::GenericPredicates<'tcx> -{ - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_super_predicates(&*cdata, def.index, tcx) -} - -pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>, - def: DefId) - -> Option -{ - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_impl_polarity(&*cdata, def.index) -} - -pub fn get_custom_coerce_unsized_kind<'tcx>( - tcx: &ty::ctxt<'tcx>, - def: DefId) - -> Option -{ - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_custom_coerce_unsized_kind(&*cdata, def.index) -} - -// Given a def_id for an impl, return the trait it implements, -// if there is one. -pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>, - def: DefId) - -> Option> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_impl_trait(&*cdata, def.index, tcx) -} - -pub fn get_native_libraries(cstore: &cstore::CStore, crate_num: ast::CrateNum) - -> Vec<(cstore::NativeLibraryKind, String)> { - let cdata = cstore.get_crate_data(crate_num); - decoder::get_native_libraries(&*cdata) -} - -pub fn each_inherent_implementation_for_type(cstore: &cstore::CStore, - def_id: DefId, - callback: F) where - F: FnMut(DefId), -{ - let cdata = cstore.get_crate_data(def_id.krate); - decoder::each_inherent_implementation_for_type(&*cdata, def_id.index, callback) -} - -pub fn each_implementation_for_trait(cstore: &cstore::CStore, - def_id: DefId, - mut callback: F) where - F: FnMut(DefId), -{ - cstore.iter_crate_data(|_, cdata| { - decoder::each_implementation_for_trait(cdata, def_id, &mut callback) - }) -} - -/// If the given def ID describes an item belonging to a trait (either a -/// default method or an implementation of a trait method), returns the ID of -/// the trait that the method belongs to. Otherwise, returns `None`. -pub fn get_trait_of_item(cstore: &cstore::CStore, - def_id: DefId, - tcx: &ty::ctxt) - -> Option { - let cdata = cstore.get_crate_data(def_id.krate); - decoder::get_trait_of_item(&*cdata, def_id.index, tcx) -} - -pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore, - def_id: DefId) - -> Option -{ - let cdata = cstore.get_crate_data(def_id.krate); - decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.index) -} - -pub fn get_dylib_dependency_formats(cstore: &cstore::CStore, - cnum: ast::CrateNum) - -> Vec<(ast::CrateNum, cstore::LinkagePreference)> -{ - let cdata = cstore.get_crate_data(cnum); - decoder::get_dylib_dependency_formats(&*cdata) -} - -pub fn get_missing_lang_items(cstore: &cstore::CStore, cnum: ast::CrateNum) - -> Vec -{ - let cdata = cstore.get_crate_data(cnum); - decoder::get_missing_lang_items(&*cdata) -} - -pub fn get_method_arg_names(cstore: &cstore::CStore, did: DefId) - -> Vec -{ - let cdata = cstore.get_crate_data(did.krate); - decoder::get_method_arg_names(&*cdata, did.index) -} - -pub fn get_reachable_ids(cstore: &cstore::CStore, cnum: ast::CrateNum) - -> Vec -{ - let cdata = cstore.get_crate_data(cnum); - decoder::get_reachable_ids(&*cdata) -} - -pub fn is_typedef(cstore: &cstore::CStore, did: DefId) -> bool { - let cdata = cstore.get_crate_data(did.krate); - decoder::is_typedef(&*cdata, did.index) -} - -pub fn is_const_fn(cstore: &cstore::CStore, did: DefId) -> bool { - let cdata = cstore.get_crate_data(did.krate); - decoder::is_const_fn(&*cdata, did.index) -} - -pub fn is_static(cstore: &cstore::CStore, did: DefId) -> bool { - let cdata = cstore.get_crate_data(did.krate); - decoder::is_static(&*cdata, did.index) -} - -pub fn is_impl(cstore: &cstore::CStore, did: DefId) -> bool { - let cdata = cstore.get_crate_data(did.krate); - decoder::is_impl(&*cdata, did.index) -} - -pub fn get_stability(cstore: &cstore::CStore, - def: DefId) - -> Option { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_stability(&*cdata, def.index) -} - -pub fn is_staged_api(cstore: &cstore::CStore, krate: ast::CrateNum) -> bool { - cstore.get_crate_data(krate).staged_api -} - -pub fn get_repr_attrs(cstore: &cstore::CStore, def: DefId) - -> Vec { - let cdata = cstore.get_crate_data(def.krate); - decoder::get_repr_attrs(&*cdata, def.index) -} - -pub fn is_defaulted_trait(cstore: &cstore::CStore, trait_def_id: DefId) -> bool { - let cdata = cstore.get_crate_data(trait_def_id.krate); - decoder::is_defaulted_trait(&*cdata, trait_def_id.index) -} - -pub fn is_default_impl(cstore: &cstore::CStore, impl_did: DefId) -> bool { - let cdata = cstore.get_crate_data(impl_did.krate); - decoder::is_default_impl(&*cdata, impl_did.index) -} - -pub fn is_extern_fn(cstore: &cstore::CStore, did: DefId, - tcx: &ty::ctxt) -> bool { - let cdata = cstore.get_crate_data(did.krate); - decoder::is_extern_fn(&*cdata, did.index, tcx) -} - -pub fn closure_kind<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind { - assert!(!def_id.is_local()); - let cdata = tcx.sess.cstore.get_crate_data(def_id.krate); - decoder::closure_kind(&*cdata, def_id.index) -} - -pub fn closure_ty<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { - assert!(!def_id.is_local()); - let cdata = tcx.sess.cstore.get_crate_data(def_id.krate); - decoder::closure_ty(&*cdata, def_id.index, tcx) -} - -pub fn def_path(tcx: &ty::ctxt, def: DefId) -> ast_map::DefPath { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - let path = decoder::def_path(&*cdata, def.index); - let local_path = cdata.local_def_path(); - local_path.into_iter().chain(path).collect() -} diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs deleted file mode 100644 index 706033f815c..00000000000 --- a/src/librustc/metadata/cstore.rs +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types)] - -// The crate store - a central repo for information collected about external -// crates and libraries - -pub use self::MetadataBlob::*; -pub use self::LinkagePreference::*; -pub use self::NativeLibraryKind::*; - -use back::svh::Svh; -use metadata::{creader, decoder, index, loader}; -use session::search_paths::PathKind; -use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; - -use std::cell::{RefCell, Ref, Cell}; -use std::rc::Rc; -use std::path::PathBuf; -use flate::Bytes; -use syntax::ast; -use syntax::attr; -use syntax::codemap; -use syntax::parse::token; -use syntax::parse::token::IdentInterner; -use syntax::util::small_vector::SmallVector; -use front::map as 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 -// crate may refer to types in other external crates, and each has their -// own crate numbers. -pub type cnum_map = FnvHashMap; - -pub enum MetadataBlob { - MetadataVec(Bytes), - MetadataArchive(loader::ArchiveMetadata), -} - -/// Holds information about a codemap::FileMap imported from another crate. -/// See creader::import_codemap() for more information. -pub struct ImportedFileMap { - /// This FileMap's byte-offset within the codemap of its original crate - pub original_start_pos: codemap::BytePos, - /// The end of this FileMap within the codemap of its original crate - pub original_end_pos: codemap::BytePos, - /// The imported FileMap's representation within the local codemap - pub translated_filemap: Rc -} - -pub struct crate_metadata { - pub name: String, - pub local_path: RefCell>, - pub local_def_path: RefCell, - pub data: MetadataBlob, - pub cnum_map: RefCell, - pub cnum: ast::CrateNum, - pub codemap_import_info: RefCell>, - pub span: codemap::Span, - pub staged_api: bool, - - pub index: index::Index, - pub xref_index: index::DenseIndex, - - /// Flag if this crate is required by an rlib version of this crate, or in - /// other words whether it was explicitly linked to. An example of a crate - /// where this is false is when an allocator crate is injected into the - /// dependency list, and therefore isn't actually needed to link an rlib. - pub explicitly_linked: Cell, -} - -#[derive(Copy, Debug, PartialEq, Clone)] -pub enum LinkagePreference { - RequireDynamic, - RequireStatic, -} - -enum_from_u32! { - #[derive(Copy, Clone, PartialEq)] - pub enum NativeLibraryKind { - NativeStatic, // native static library (.a archive) - NativeFramework, // OSX-specific - NativeUnknown, // default way to specify a dynamic library - } -} - -// Where a crate came from on the local filesystem. One of these two options -// must be non-None. -#[derive(PartialEq, Clone, Debug)] -pub struct CrateSource { - pub dylib: Option<(PathBuf, PathKind)>, - pub rlib: Option<(PathBuf, PathKind)>, - pub cnum: ast::CrateNum, -} - -pub struct CStore { - metas: RefCell>>, - /// Map from NodeId's of local extern crate statements to crate numbers - extern_mod_crate_map: RefCell>, - used_crate_sources: RefCell>, - used_libraries: RefCell>, - used_link_args: RefCell>, - statically_included_foreign_items: RefCell, - pub intr: Rc, -} - -/// Item definitions in the currently-compiled crate would have the CrateNum -/// LOCAL_CRATE in their DefId. -pub const LOCAL_CRATE: ast::CrateNum = 0; - -impl CStore { - pub fn new(intr: Rc) -> CStore { - CStore { - metas: RefCell::new(FnvHashMap()), - extern_mod_crate_map: RefCell::new(FnvHashMap()), - used_crate_sources: RefCell::new(Vec::new()), - used_libraries: RefCell::new(Vec::new()), - used_link_args: RefCell::new(Vec::new()), - intr: intr, - statically_included_foreign_items: RefCell::new(NodeSet()), - } - } - - pub fn next_crate_num(&self) -> ast::CrateNum { - self.metas.borrow().len() as ast::CrateNum + 1 - } - - pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc { - self.metas.borrow().get(&cnum).unwrap().clone() - } - - pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh { - let cdata = self.get_crate_data(cnum); - decoder::get_crate_hash(cdata.data()) - } - - pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc) { - self.metas.borrow_mut().insert(cnum, data); - } - - pub fn iter_crate_data(&self, mut i: I) where - I: FnMut(ast::CrateNum, &Rc), - { - for (&k, v) in self.metas.borrow().iter() { - i(k, v); - } - } - - /// Like `iter_crate_data`, but passes source paths (if available) as well. - pub fn iter_crate_data_origins(&self, mut i: I) where - I: FnMut(ast::CrateNum, &crate_metadata, Option), - { - for (&k, v) in self.metas.borrow().iter() { - let origin = self.do_get_used_crate_source(k); - origin.as_ref().map(|cs| { assert!(k == cs.cnum); }); - i(k, &**v, origin); - } - } - - pub fn add_used_crate_source(&self, src: CrateSource) { - let mut used_crate_sources = self.used_crate_sources.borrow_mut(); - if !used_crate_sources.contains(&src) { - used_crate_sources.push(src); - } - } - - // TODO: killdo - pub fn do_get_used_crate_source(&self, cnum: ast::CrateNum) - -> Option { - self.used_crate_sources.borrow_mut() - .iter().find(|source| source.cnum == cnum).cloned() - } - - pub fn reset(&self) { - self.metas.borrow_mut().clear(); - self.extern_mod_crate_map.borrow_mut().clear(); - self.used_crate_sources.borrow_mut().clear(); - self.used_libraries.borrow_mut().clear(); - self.used_link_args.borrow_mut().clear(); - self.statically_included_foreign_items.borrow_mut().clear(); - } - - // This method is used when generating the command line to pass through to - // system linker. The linker expects undefined symbols on the left of the - // command line to be defined in libraries on the right, not the other way - // around. For more info, see some comments in the add_used_library function - // below. - // - // In order to get this left-to-right dependency ordering, we perform a - // topological sort of all crates putting the leaves at the right-most - // positions. - // TODO: killdo - pub fn do_get_used_crates(&self, prefer: LinkagePreference) - -> Vec<(ast::CrateNum, Option)> { - let mut ordering = Vec::new(); - fn visit(cstore: &CStore, cnum: ast::CrateNum, - ordering: &mut Vec) { - if ordering.contains(&cnum) { return } - let meta = cstore.get_crate_data(cnum); - for (_, &dep) in meta.cnum_map.borrow().iter() { - visit(cstore, dep, ordering); - } - ordering.push(cnum); - } - for (&num, _) in self.metas.borrow().iter() { - visit(self, num, &mut ordering); - } - info!("topological ordering: {:?}", ordering); - ordering.reverse(); - let mut libs = self.used_crate_sources.borrow() - .iter() - .map(|src| (src.cnum, match prefer { - RequireDynamic => src.dylib.clone().map(|p| p.0), - RequireStatic => src.rlib.clone().map(|p| p.0), - })) - .collect::>(); - libs.sort_by(|&(a, _), &(b, _)| { - let a = ordering.iter().position(|x| *x == a); - let b = ordering.iter().position(|x| *x == b); - a.cmp(&b) - }); - libs - } - - pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) { - assert!(!lib.is_empty()); - self.used_libraries.borrow_mut().push((lib, kind)); - } - - pub fn get_used_libraries<'a>(&'a self) - -> &'a RefCell> { - &self.used_libraries - } - - pub fn add_used_link_args(&self, args: &str) { - for s in args.split(' ').filter(|s| !s.is_empty()) { - self.used_link_args.borrow_mut().push(s.to_string()); - } - } - - pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell > { - &self.used_link_args - } - - pub fn add_extern_mod_stmt_cnum(&self, - emod_id: ast::NodeId, - cnum: ast::CrateNum) { - self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum); - } - - pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) - -> Option { - self.extern_mod_crate_map.borrow().get(&emod_id).cloned() - } - - pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) { - self.statically_included_foreign_items.borrow_mut().insert(id); - } - - pub fn do_is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { - self.statically_included_foreign_items.borrow().contains(&id) - } -} - -impl crate_metadata { - pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } - pub fn name(&self) -> String { decoder::get_crate_name(self.data()) } - pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) } - pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap) - -> Ref<'a, Vec> { - let filemaps = self.codemap_import_info.borrow(); - if filemaps.is_empty() { - drop(filemaps); - let filemaps = creader::import_codemap(codemap, &self.data); - - // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref. - *self.codemap_import_info.borrow_mut() = filemaps; - self.codemap_import_info.borrow() - } else { - filemaps - } - } - - pub fn with_local_path(&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; - } - }, - } - } - - pub fn local_def_path(&self) -> ast_map::DefPath { - let local_def_path = self.local_def_path.borrow(); - if local_def_path.is_empty() { - let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name)); - vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }] - } else { - local_def_path.clone() - } - } - - pub fn update_local_def_path(&self, candidate: ast_map::DefPath) { - let mut local_def_path = self.local_def_path.borrow_mut(); - if local_def_path.is_empty() || candidate.len() < local_def_path.len() { - *local_def_path = candidate; - } - } - - pub fn is_allocator(&self) -> bool { - let attrs = decoder::get_crate_attributes(self.data()); - attr::contains_name(&attrs, "allocator") - } - - pub fn needs_allocator(&self) -> bool { - let attrs = decoder::get_crate_attributes(self.data()); - attr::contains_name(&attrs, "needs_allocator") - } -} - -impl MetadataBlob { - pub fn as_slice<'a>(&'a self) -> &'a [u8] { - let slice = match *self { - MetadataVec(ref vec) => &vec[..], - MetadataArchive(ref ar) => ar.as_slice(), - }; - if slice.len() < 4 { - &[] // corrupt metadata - } else { - let len = (((slice[0] as u32) << 24) | - ((slice[1] as u32) << 16) | - ((slice[2] as u32) << 8) | - ((slice[3] as u32) << 0)) as usize; - if len + 4 <= slice.len() { - &slice[4.. len + 4] - } else { - &[] // corrupt or old metadata - } - } - } -} diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs deleted file mode 100644 index 84a95f04795..00000000000 --- a/src/librustc/metadata/decoder.rs +++ /dev/null @@ -1,1567 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Decoding metadata from a single crate's metadata - -#![allow(non_camel_case_types)] - -pub use self::DefLike::*; -use self::Family::*; - -use front::map as hir_map; -use rustc_front::hir; - -use back::svh::Svh; -use metadata::cstore::crate_metadata; -use metadata::cstore::LOCAL_CRATE; -use metadata::common::*; -use metadata::cstore; -use metadata::encoder::def_to_u64; -use metadata::index; -use metadata::inline::InlinedItem; -use metadata::tydecode::TyDecoder; -use metadata::util::FoundAst; -use middle::def; -use middle::def_id::{DefId, DefIndex}; -use middle::lang_items; -use middle::subst; -use middle::ty::{ImplContainer, TraitContainer}; -use middle::ty::{self, RegionEscape, Ty}; -use util::nodemap::FnvHashMap; - -use std::cell::{Cell, RefCell}; -use std::io::prelude::*; -use std::io; -use std::rc::Rc; -use std::str; - -use rbml::reader; -use rbml; -use serialize::Decodable; -use syntax::attr; -use syntax::parse::token::{IdentInterner, special_idents}; -use syntax::parse::token; -use syntax::ast; -use syntax::abi; -use syntax::codemap; -use syntax::print::pprust; -use syntax::ptr::P; - - -pub type Cmd<'a> = &'a crate_metadata; - -impl crate_metadata { - fn get_item(&self, item_id: DefIndex) -> Option { - self.index.lookup_item(self.data(), item_id).map(|pos| { - reader::doc_at(self.data(), pos as usize).unwrap().doc - }) - } - - fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc { - match self.get_item(item_id) { - None => panic!("lookup_item: id not found: {:?}", item_id), - Some(d) => d - } - } -} - -pub fn load_index(data: &[u8]) -> index::Index { - let index = reader::get_doc(rbml::Doc::new(data), tag_index); - index::Index::from_rbml(index) -} - -pub fn crate_rustc_version(data: &[u8]) -> Option { - let doc = rbml::Doc::new(data); - reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str()) -} - -pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { - let index = reader::get_doc(rbml::Doc::new(data), tag_xref_index); - index::DenseIndex::from_buf(index.data, index.start, index.end) -} - -#[derive(Debug, PartialEq)] -enum Family { - ImmStatic, // c - MutStatic, // b - Fn, // f - CtorFn, // o - StaticMethod, // F - Method, // h - Type, // y - Mod, // m - ForeignMod, // n - Enum, // t - TupleVariant, // v - StructVariant, // V - Impl, // i - DefaultImpl, // d - Trait, // I - Struct, // S - PublicField, // g - InheritedField, // N - Constant, // C -} - -fn item_family(item: rbml::Doc) -> Family { - let fam = reader::get_doc(item, tag_items_data_item_family); - match reader::doc_as_u8(fam) as char { - 'C' => Constant, - 'c' => ImmStatic, - 'b' => MutStatic, - 'f' => Fn, - 'o' => CtorFn, - 'F' => StaticMethod, - 'h' => Method, - 'y' => Type, - 'm' => Mod, - 'n' => ForeignMod, - 't' => Enum, - 'v' => TupleVariant, - 'V' => StructVariant, - 'i' => Impl, - 'd' => DefaultImpl, - 'I' => Trait, - 'S' => Struct, - 'g' => PublicField, - 'N' => InheritedField, - c => panic!("unexpected family char: {}", c) - } -} - -fn item_visibility(item: rbml::Doc) -> hir::Visibility { - match reader::maybe_get_doc(item, tag_items_data_item_visibility) { - None => hir::Public, - Some(visibility_doc) => { - match reader::doc_as_u8(visibility_doc) as char { - 'y' => hir::Public, - 'i' => hir::Inherited, - _ => panic!("unknown visibility character") - } - } - } -} - -fn fn_constness(item: rbml::Doc) -> hir::Constness { - match reader::maybe_get_doc(item, tag_items_data_item_constness) { - None => hir::Constness::NotConst, - Some(constness_doc) => { - match reader::doc_as_u8(constness_doc) as char { - 'c' => hir::Constness::Const, - 'n' => hir::Constness::NotConst, - _ => panic!("unknown constness character") - } - } - } -} - -fn item_sort(item: rbml::Doc) -> Option { - reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| { - doc.as_str_slice().as_bytes()[0] as char - }) -} - -fn item_symbol(item: rbml::Doc) -> String { - reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string() -} - -fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { - let id = reader::doc_as_u64(d); - let index = DefIndex::new((id & 0xFFFF_FFFF) as usize); - let def_id = DefId { krate: (id >> 32) as u32, index: index }; - translate_def_id(cdata, def_id) -} - -fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { - reader::tagged_docs(d, tag_items_data_parent_item).nth(0).map(|did| { - translated_def_id(cdata, did) - }) -} - -fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId { - translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item)) -} - -fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId { - translated_def_id(cdata, reader::get_doc(d, tag_def_id)) -} - -fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> { - reader::tagged_docs(d, tag_items_data_item_reexport) -} - -fn variant_disr_val(d: rbml::Doc) -> Option { - reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| { - reader::with_doc_data(val_doc, |data| { - str::from_utf8(data).ok().and_then(|s| s.parse().ok()) - }) - }) -} - -fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> { - let tp = reader::get_doc(doc, tag_items_data_item_type); - TyDecoder::with_doc(tcx, cdata.cnum, tp, - &mut |did| translate_def_id(cdata, did)) - .parse_ty() -} - -fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option> { - reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| { - TyDecoder::with_doc(tcx, cdata.cnum, tp, - &mut |did| translate_def_id(cdata, did)) - .parse_ty() - }) -} - -pub fn item_type<'tcx>(_item_id: DefId, item: rbml::Doc, - tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> { - doc_type(item, tcx, cdata) -} - -fn doc_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) - -> ty::TraitRef<'tcx> { - TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |did| translate_def_id(cdata, did)) - .parse_trait_ref() -} - -fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) - -> ty::TraitRef<'tcx> { - let tp = reader::get_doc(doc, tag_item_trait_ref); - doc_trait_ref(tp, tcx, cdata) -} - -fn item_path(item_doc: rbml::Doc) -> Vec { - let path_doc = reader::get_doc(item_doc, tag_path); - reader::docs(path_doc).filter_map(|(tag, elt_doc)| { - if tag == tag_path_elem_mod { - let s = elt_doc.as_str_slice(); - Some(hir_map::PathMod(token::intern(s))) - } else if tag == tag_path_elem_name { - let s = elt_doc.as_str_slice(); - Some(hir_map::PathName(token::intern(s))) - } else { - // ignore tag_path_len element - None - } - }).collect() -} - -fn item_name(intr: &IdentInterner, item: rbml::Doc) -> ast::Name { - let name = reader::get_doc(item, tag_paths_data_name); - let string = name.as_str_slice(); - match intr.find(string) { - None => token::intern(string), - Some(val) => val, - } -} - -fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike { - let fam = item_family(item); - match fam { - Constant => { - // Check whether we have an associated const item. - match item_sort(item) { - Some('C') | Some('c') => { - DlDef(def::DefAssociatedConst(did)) - } - _ => { - // Regular const item. - DlDef(def::DefConst(did)) - } - } - } - ImmStatic => DlDef(def::DefStatic(did, false)), - MutStatic => DlDef(def::DefStatic(did, true)), - Struct => DlDef(def::DefStruct(did)), - Fn => DlDef(def::DefFn(did, false)), - CtorFn => DlDef(def::DefFn(did, true)), - Method | StaticMethod => { - DlDef(def::DefMethod(did)) - } - Type => { - if item_sort(item) == Some('t') { - let trait_did = item_require_parent_item(cdata, item); - DlDef(def::DefAssociatedTy(trait_did, did)) - } else { - DlDef(def::DefTy(did, false)) - } - } - Mod => DlDef(def::DefMod(did)), - ForeignMod => DlDef(def::DefForeignMod(did)), - StructVariant => { - let enum_did = item_require_parent_item(cdata, item); - DlDef(def::DefVariant(enum_did, did, true)) - } - TupleVariant => { - let enum_did = item_require_parent_item(cdata, item); - DlDef(def::DefVariant(enum_did, did, false)) - } - Trait => DlDef(def::DefTrait(did)), - Enum => DlDef(def::DefTy(did, true)), - Impl | DefaultImpl => DlImpl(did), - PublicField | InheritedField => DlField, - } -} - -fn parse_unsafety(item_doc: rbml::Doc) -> hir::Unsafety { - let unsafety_doc = reader::get_doc(item_doc, tag_unsafety); - if reader::doc_as_u8(unsafety_doc) != 0 { - hir::Unsafety::Unsafe - } else { - hir::Unsafety::Normal - } -} - -fn parse_paren_sugar(item_doc: rbml::Doc) -> bool { - let paren_sugar_doc = reader::get_doc(item_doc, tag_paren_sugar); - reader::doc_as_u8(paren_sugar_doc) != 0 -} - -fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity { - let polarity_doc = reader::get_doc(item_doc, tag_polarity); - if reader::doc_as_u8(polarity_doc) != 0 { - hir::ImplPolarity::Negative - } else { - hir::ImplPolarity::Positive - } -} - -fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { - let names_doc = reader::get_doc(item_doc, tag_associated_type_names); - reader::tagged_docs(names_doc, tag_associated_type_name) - .map(|name_doc| token::intern(name_doc.as_str_slice())) - .collect() -} - -pub fn get_trait_def<'tcx>(cdata: Cmd, - item_id: DefIndex, - tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx> -{ - let item_doc = cdata.lookup_item(item_id); - let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); - let unsafety = parse_unsafety(item_doc); - let associated_type_names = parse_associated_type_names(item_doc); - let paren_sugar = parse_paren_sugar(item_doc); - - ty::TraitDef { - paren_sugar: paren_sugar, - unsafety: unsafety, - generics: generics, - trait_ref: item_trait_ref(item_doc, tcx, cdata), - associated_type_names: associated_type_names, - nonblanket_impls: RefCell::new(FnvHashMap()), - blanket_impls: RefCell::new(vec![]), - flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS) - } -} - -pub fn get_adt_def<'tcx>(intr: &IdentInterner, - cdata: Cmd, - item_id: DefIndex, - tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx> -{ - fn get_enum_variants<'tcx>(intr: &IdentInterner, - cdata: Cmd, - doc: rbml::Doc, - tcx: &ty::ctxt<'tcx>) -> Vec> { - let mut disr_val = 0; - reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| { - let did = translated_def_id(cdata, p); - let item = cdata.lookup_item(did.index); - - if let Some(disr) = variant_disr_val(item) { - disr_val = disr; - } - let disr = disr_val; - disr_val = disr_val.wrapping_add(1); - - ty::VariantDefData { - did: did, - name: item_name(intr, item), - fields: get_variant_fields(intr, cdata, item, tcx), - disr_val: disr - } - }).collect() - } - fn get_variant_fields<'tcx>(intr: &IdentInterner, - cdata: Cmd, - doc: rbml::Doc, - tcx: &ty::ctxt<'tcx>) -> Vec> { - reader::tagged_docs(doc, tag_item_field).map(|f| { - let ff = item_family(f); - match ff { - PublicField | InheritedField => {}, - _ => tcx.sess.bug(&format!("expected field, found {:?}", ff)) - }; - ty::FieldDefData::new(item_def_id(f, cdata), - item_name(intr, f), - struct_field_family_to_visibility(ff)) - }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| { - let ff = item_family(f); - ty::FieldDefData::new(item_def_id(f, cdata), - special_idents::unnamed_field.name, - struct_field_family_to_visibility(ff)) - })).collect() - } - fn get_struct_variant<'tcx>(intr: &IdentInterner, - cdata: Cmd, - doc: rbml::Doc, - did: DefId, - tcx: &ty::ctxt<'tcx>) -> ty::VariantDefData<'tcx, 'tcx> { - ty::VariantDefData { - did: did, - name: item_name(intr, doc), - fields: get_variant_fields(intr, cdata, doc, tcx), - disr_val: 0 - } - } - - let doc = cdata.lookup_item(item_id); - let did = DefId { krate: cdata.cnum, index: item_id }; - let (kind, variants) = match item_family(doc) { - Enum => { - (ty::AdtKind::Enum, - get_enum_variants(intr, cdata, doc, tcx)) - } - Struct => { - let ctor_did = - reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor). - map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc)); - (ty::AdtKind::Struct, - vec![get_struct_variant(intr, cdata, doc, ctor_did, tcx)]) - } - _ => tcx.sess.bug( - &format!("get_adt_def called on a non-ADT {:?} - {:?}", - item_family(doc), did)) - }; - - let adt = tcx.intern_adt_def(did, kind, variants); - - // this needs to be done *after* the variant is interned, - // to support recursive structures - for variant in &adt.variants { - if variant.kind() == ty::VariantKind::Tuple && - adt.adt_kind() == ty::AdtKind::Enum { - // tuple-like enum variant fields aren't real items - get the types - // from the ctor. - debug!("evaluating the ctor-type of {:?}", - variant.name); - let ctor_ty = get_type(cdata, variant.did.index, tcx).ty; - debug!("evaluating the ctor-type of {:?}.. {:?}", - variant.name, - ctor_ty); - let field_tys = match ctor_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { - ref inputs, .. - }), ..}) => { - // tuple-struct constructors don't have escaping regions - assert!(!inputs.has_escaping_regions()); - inputs - }, - _ => tcx.sess.bug("tuple-variant ctor is not an ADT") - }; - for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) { - field.fulfill_ty(ty); - } - } else { - for field in &variant.fields { - debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); - let ty = get_type(cdata, field.did.index, tcx).ty; - field.fulfill_ty(ty); - debug!("evaluating the type of {:?}::{:?}: {:?}", - variant.name, field.name, ty); - } - } - } - - adt -} - -pub fn get_predicates<'tcx>(cdata: Cmd, - item_id: DefIndex, - tcx: &ty::ctxt<'tcx>) - -> ty::GenericPredicates<'tcx> -{ - let item_doc = cdata.lookup_item(item_id); - doc_predicates(item_doc, tcx, cdata, tag_item_generics) -} - -pub fn get_super_predicates<'tcx>(cdata: Cmd, - item_id: DefIndex, - tcx: &ty::ctxt<'tcx>) - -> ty::GenericPredicates<'tcx> -{ - let item_doc = cdata.lookup_item(item_id); - doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates) -} - -pub fn get_type<'tcx>(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt<'tcx>) - -> ty::TypeScheme<'tcx> -{ - let item_doc = cdata.lookup_item(id); - let t = item_type(DefId { krate: cdata.cnum, index: id }, item_doc, tcx, - cdata); - let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); - ty::TypeScheme { - generics: generics, - ty: t - } -} - -pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { - let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| { - let mut decoder = reader::Decoder::new(doc); - Decodable::decode(&mut decoder).unwrap() - }) -} - -pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { - let item = cdata.lookup_item(id); - match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| { - let mut decoder = reader::Decoder::new(doc); - Decodable::decode(&mut decoder).unwrap() - }) { - Some(attrs) => attrs, - None => Vec::new(), - } -} - -pub fn get_impl_polarity<'tcx>(cdata: Cmd, - id: DefIndex) - -> Option -{ - let item_doc = cdata.lookup_item(id); - let fam = item_family(item_doc); - match fam { - Family::Impl => { - Some(parse_polarity(item_doc)) - } - _ => None - } -} - -pub fn get_custom_coerce_unsized_kind<'tcx>( - cdata: Cmd, - id: DefIndex) - -> Option -{ - let item_doc = cdata.lookup_item(id); - reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { - let mut decoder = reader::Decoder::new(kind_doc); - Decodable::decode(&mut decoder).unwrap() - }) -} - -pub fn get_impl_trait<'tcx>(cdata: Cmd, - id: DefIndex, - tcx: &ty::ctxt<'tcx>) - -> Option> -{ - let item_doc = cdata.lookup_item(id); - let fam = item_family(item_doc); - match fam { - Family::Impl | Family::DefaultImpl => { - reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { - doc_trait_ref(tp, tcx, cdata) - }) - } - _ => None - } -} - -pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String { - return item_symbol(cdata.lookup_item(id)); -} - -/// If you have a crate_metadata, call get_symbol instead -pub fn get_symbol_from_buf(data: &[u8], id: DefIndex) -> String { - let index = load_index(data); - let pos = index.lookup_item(data, id).unwrap(); - let doc = reader::doc_at(data, pos as usize).unwrap().doc; - item_symbol(doc) -} - -// Something that a name can resolve to. -#[derive(Copy, Clone, Debug)] -pub enum DefLike { - DlDef(def::Def), - DlImpl(DefId), - DlField -} - -/// Iterates over the language items in the given crate. -pub fn each_lang_item(cdata: Cmd, mut f: F) -> bool where - F: FnMut(DefIndex, usize) -> bool, -{ - let root = rbml::Doc::new(cdata.data()); - let lang_items = reader::get_doc(root, tag_lang_items); - reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| { - let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id); - let id = reader::doc_as_u32(id_doc) as usize; - let index_doc = reader::get_doc(item_doc, tag_lang_items_item_index); - let index = DefIndex::from_u32(reader::doc_as_u32(index_doc)); - - f(index, id) - }) -} - -fn each_child_of_item_or_crate(intr: Rc, - cdata: Cmd, - item_doc: rbml::Doc, - mut get_crate_data: G, - mut callback: F) where - F: FnMut(DefLike, ast::Name, hir::Visibility), - G: FnMut(ast::CrateNum) -> Rc, -{ - // Iterate over all children. - for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) { - let child_def_id = translated_def_id(cdata, child_info_doc); - - // This item may be in yet another crate if it was the child of a - // reexport. - let crate_data = if child_def_id.krate == cdata.cnum { - None - } else { - Some(get_crate_data(child_def_id.krate)) - }; - let crate_data = match crate_data { - Some(ref cdata) => &**cdata, - None => cdata - }; - - // Get the item. - match crate_data.get_item(child_def_id.index) { - None => {} - Some(child_item_doc) => { - // Hand off the item to the callback. - let child_name = item_name(&*intr, child_item_doc); - let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); - let visibility = item_visibility(child_item_doc); - callback(def_like, child_name, visibility); - } - } - } - - // As a special case, iterate over all static methods of - // associated implementations too. This is a bit of a botch. - // --pcwalton - for inherent_impl_def_id_doc in reader::tagged_docs(item_doc, - tag_items_data_item_inherent_impl) { - let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata); - if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.index) { - for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc, - tag_item_impl_item) { - let impl_item_def_id = item_def_id(impl_item_def_id_doc, - cdata); - if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.index) { - if let StaticMethod = item_family(impl_method_doc) { - // Hand off the static method to the callback. - let static_method_name = item_name(&*intr, impl_method_doc); - let static_method_def_like = item_to_def_like(cdata, impl_method_doc, - impl_item_def_id); - callback(static_method_def_like, - static_method_name, - item_visibility(impl_method_doc)); - } - } - } - } - } - - for reexport_doc in reexports(item_doc) { - let def_id_doc = reader::get_doc(reexport_doc, - tag_items_data_item_reexport_def_id); - let child_def_id = translated_def_id(cdata, def_id_doc); - - let name_doc = reader::get_doc(reexport_doc, - tag_items_data_item_reexport_name); - let name = name_doc.as_str_slice(); - - // This reexport may be in yet another crate. - let crate_data = if child_def_id.krate == cdata.cnum { - None - } else { - Some(get_crate_data(child_def_id.krate)) - }; - let crate_data = match crate_data { - Some(ref cdata) => &**cdata, - None => cdata - }; - - // Get the item. - if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) { - // Hand off the item to the callback. - let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); - // These items have a public visibility because they're part of - // a public re-export. - callback(def_like, token::intern(name), hir::Public); - } - } -} - -/// Iterates over each child of the given item. -pub fn each_child_of_item(intr: Rc, - cdata: Cmd, - id: DefIndex, - get_crate_data: G, - callback: F) where - F: FnMut(DefLike, ast::Name, hir::Visibility), - G: FnMut(ast::CrateNum) -> Rc, -{ - // Find the item. - let item_doc = match cdata.get_item(id) { - None => return, - Some(item_doc) => item_doc, - }; - - each_child_of_item_or_crate(intr, - cdata, - item_doc, - get_crate_data, - callback) -} - -/// Iterates over all the top-level crate items. -pub fn each_top_level_item_of_crate(intr: Rc, - cdata: Cmd, - get_crate_data: G, - callback: F) where - F: FnMut(DefLike, ast::Name, hir::Visibility), - G: FnMut(ast::CrateNum) -> Rc, -{ - let root_doc = rbml::Doc::new(cdata.data()); - let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); - let crate_items_doc = reader::get_doc(misc_info_doc, - tag_misc_info_crate_items); - - each_child_of_item_or_crate(intr, - cdata, - crate_items_doc, - get_crate_data, - callback) -} - -pub fn get_item_path(cdata: Cmd, id: DefIndex) -> Vec { - item_path(cdata.lookup_item(id)) -} - -pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: DefIndex) -> ast::Name { - item_name(intr, cdata.lookup_item(id)) -} - -pub type DecodeInlinedItem<'a> = - Box FnMut(Cmd, - &ty::ctxt<'tcx>, - Vec, - hir_map::DefPath, - rbml::Doc, - DefId) - -> Result<&'tcx InlinedItem, (Vec, - hir_map::DefPath)> + 'a>; - -pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex, - mut decode_inlined_item: DecodeInlinedItem) - -> FoundAst<'tcx> { - debug!("Looking up item: {:?}", id); - let item_doc = cdata.lookup_item(id); - let item_did = item_def_id(item_doc, cdata); - let path = item_path(item_doc).split_last().unwrap().1.to_vec(); - let def_path = def_path(cdata, id); - match decode_inlined_item(cdata, tcx, path, def_path, item_doc, item_did) { - Ok(ii) => FoundAst::Found(ii), - Err((path, def_path)) => { - match item_parent_item(cdata, item_doc) { - Some(did) => { - let parent_item = cdata.lookup_item(did.index); - match decode_inlined_item(cdata, tcx, path, def_path, parent_item, did) { - Ok(ii) => FoundAst::FoundParent(did, ii), - Err(_) => FoundAst::NotFound - } - } - None => FoundAst::NotFound - } - } - } -} - -fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { - fn get_mutability(ch: u8) -> hir::Mutability { - match ch as char { - 'i' => hir::MutImmutable, - 'm' => hir::MutMutable, - _ => panic!("unknown mutability character: `{}`", ch as char), - } - } - - let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self); - let string = explicit_self_doc.as_str_slice(); - - let explicit_self_kind = string.as_bytes()[0]; - match explicit_self_kind as char { - 's' => ty::StaticExplicitSelfCategory, - 'v' => ty::ByValueExplicitSelfCategory, - '~' => ty::ByBoxExplicitSelfCategory, - // FIXME(#4846) expl. region - '&' => { - ty::ByReferenceExplicitSelfCategory( - ty::ReEmpty, - get_mutability(string.as_bytes()[1])) - } - _ => panic!("unknown self type code: `{}`", explicit_self_kind as char) - } -} - -/// Returns the def IDs of all the items in the given implementation. -pub fn get_impl_items(cdata: Cmd, impl_id: DefIndex) - -> Vec { - reader::tagged_docs(cdata.lookup_item(impl_id), tag_item_impl_item).map(|doc| { - let def_id = item_def_id(doc, cdata); - match item_sort(doc) { - Some('C') | Some('c') => ty::ConstTraitItemId(def_id), - Some('r') | Some('p') => ty::MethodTraitItemId(def_id), - Some('t') => ty::TypeTraitItemId(def_id), - _ => panic!("unknown impl item sort"), - } - }).collect() -} - -pub fn get_trait_name(intr: Rc, - cdata: Cmd, - id: DefIndex) - -> ast::Name { - let doc = cdata.lookup_item(id); - item_name(&*intr, doc) -} - -pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool { - let doc = cdata.lookup_item(id); - match item_sort(doc) { - Some('r') | Some('p') => { - get_explicit_self(doc) == ty::StaticExplicitSelfCategory - } - _ => false - } -} - -pub fn get_impl_or_trait_item<'tcx>(intr: Rc, - cdata: Cmd, - id: DefIndex, - tcx: &ty::ctxt<'tcx>) - -> ty::ImplOrTraitItem<'tcx> { - let item_doc = cdata.lookup_item(id); - - let def_id = item_def_id(item_doc, cdata); - - let container_id = item_require_parent_item(cdata, item_doc); - let container_doc = cdata.lookup_item(container_id.index); - let container = match item_family(container_doc) { - Trait => TraitContainer(container_id), - _ => ImplContainer(container_id), - }; - - let name = item_name(&*intr, item_doc); - let vis = item_visibility(item_doc); - - match item_sort(item_doc) { - sort @ Some('C') | sort @ Some('c') => { - let ty = doc_type(item_doc, tcx, cdata); - ty::ConstTraitItem(Rc::new(ty::AssociatedConst { - name: name, - ty: ty, - vis: vis, - def_id: def_id, - container: container, - has_value: sort == Some('C') - })) - } - Some('r') | Some('p') => { - let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics); - let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics); - let ity = tcx.lookup_item_type(def_id).ty; - let fty = match ity.sty { - ty::TyBareFn(_, fty) => fty.clone(), - _ => tcx.sess.bug(&format!( - "the type {:?} of the method {:?} is not a function?", - ity, name)) - }; - let explicit_self = get_explicit_self(item_doc); - - ty::MethodTraitItem(Rc::new(ty::Method::new(name, - generics, - predicates, - fty, - explicit_self, - vis, - def_id, - container))) - } - Some('t') => { - let ty = maybe_doc_type(item_doc, tcx, cdata); - ty::TypeTraitItem(Rc::new(ty::AssociatedType { - name: name, - ty: ty, - vis: vis, - def_id: def_id, - container: container, - })) - } - _ => panic!("unknown impl/trait item sort"), - } -} - -pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex) - -> Vec { - let item = cdata.lookup_item(id); - reader::tagged_docs(item, tag_item_trait_item).map(|mth| { - let def_id = item_def_id(mth, cdata); - match item_sort(mth) { - Some('C') | Some('c') => ty::ConstTraitItemId(def_id), - Some('r') | Some('p') => ty::MethodTraitItemId(def_id), - Some('t') => ty::TypeTraitItemId(def_id), - _ => panic!("unknown trait item sort"), - } - }).collect() -} - -pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances { - let item_doc = cdata.lookup_item(id); - let variance_doc = reader::get_doc(item_doc, tag_item_variances); - let mut decoder = reader::Decoder::new(variance_doc); - Decodable::decode(&mut decoder).unwrap() -} - -pub fn get_provided_trait_methods<'tcx>(intr: Rc, - cdata: Cmd, - id: DefIndex, - tcx: &ty::ctxt<'tcx>) - -> Vec>> { - let item = cdata.lookup_item(id); - - reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| { - let did = item_def_id(mth_id, cdata); - let mth = cdata.lookup_item(did.index); - - if item_sort(mth) == Some('p') { - let trait_item = get_impl_or_trait_item(intr.clone(), - cdata, - did.index, - tcx); - if let ty::MethodTraitItem(ref method) = trait_item { - Some((*method).clone()) - } else { - None - } - } else { - None - } - }).collect() -} - -pub fn get_associated_consts<'tcx>(intr: Rc, - cdata: Cmd, - id: DefIndex, - tcx: &ty::ctxt<'tcx>) - -> Vec>> { - let item = cdata.lookup_item(id); - - [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| { - reader::tagged_docs(item, tag).filter_map(|ac_id| { - let did = item_def_id(ac_id, cdata); - let ac_doc = cdata.lookup_item(did.index); - - match item_sort(ac_doc) { - Some('C') | Some('c') => { - let trait_item = get_impl_or_trait_item(intr.clone(), - cdata, - did.index, - tcx); - if let ty::ConstTraitItem(ref ac) = trait_item { - Some((*ac).clone()) - } else { - None - } - } - _ => None - } - }) - }).collect() -} - -/// If node_id is the constructor of a tuple struct, retrieve the NodeId of -/// the actual type definition, otherwise, return None -pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, - node_id: DefIndex) - -> Option -{ - let item = cdata.lookup_item(node_id); - reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor).next().map(|_| { - item_require_parent_item(cdata, item) - }) -} - -pub fn get_item_attrs(cdata: Cmd, - orig_node_id: DefIndex) - -> Vec { - // The attributes for a tuple struct are attached to the definition, not the ctor; - // we assume that someone passing in a tuple struct ctor is actually wanting to - // look at the definition - let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id); - let node_id = node_id.map(|x| x.index).unwrap_or(orig_node_id); - let item = cdata.lookup_item(node_id); - get_attributes(item) -} - -pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap> { - let data = rbml::Doc::new(cdata.data()); - let fields = reader::get_doc(data, tag_struct_fields); - reader::tagged_docs(fields, tag_struct_field).map(|field| { - let def_id = translated_def_id(cdata, reader::get_doc(field, tag_def_id)); - let attrs = get_attributes(field); - (def_id, attrs) - }).collect() -} - -fn struct_field_family_to_visibility(family: Family) -> hir::Visibility { - match family { - PublicField => hir::Public, - InheritedField => hir::Inherited, - _ => panic!() - } -} - -pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: DefIndex) - -> Vec { - let item = cdata.lookup_item(id); - reader::tagged_docs(item, tag_item_field).map(|an_item| { - item_name(intr, an_item) - }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|_| { - special_idents::unnamed_field.name - })).collect() -} - -fn get_meta_items(md: rbml::Doc) -> Vec> { - reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str_slice()); - attr::mk_word_item(n) - }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); - let n = token::intern_and_get_ident(nd.as_str_slice()); - let v = token::intern_and_get_ident(vd.as_str_slice()); - // FIXME (#623): Should be able to decode MetaNameValue variants, - // but currently the encoder just drops them - attr::mk_name_value_item_str(n, v) - })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str_slice()); - let subitems = get_meta_items(meta_item_doc); - attr::mk_list_item(n, subitems) - })).collect() -} - -fn get_attributes(md: rbml::Doc) -> Vec { - match reader::maybe_get_doc(md, tag_attributes) { - Some(attrs_d) => { - reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| { - let is_sugared_doc = reader::doc_as_u8( - reader::get_doc(attr_doc, tag_attribute_is_sugared_doc) - ) == 1; - let meta_items = get_meta_items(attr_doc); - // Currently it's only possible to have a single meta item on - // an attribute - assert_eq!(meta_items.len(), 1); - let meta_item = meta_items.into_iter().nth(0).unwrap(); - codemap::Spanned { - node: ast::Attribute_ { - id: attr::mk_attr_id(), - style: ast::AttrStyle::Outer, - value: meta_item, - is_sugared_doc: is_sugared_doc, - }, - span: codemap::DUMMY_SP - } - }).collect() - }, - None => vec![], - } -} - -fn list_crate_attributes(md: rbml::Doc, hash: &Svh, - out: &mut io::Write) -> io::Result<()> { - try!(write!(out, "=Crate Attributes ({})=\n", *hash)); - - let r = get_attributes(md); - for attr in &r { - try!(write!(out, "{}\n", pprust::attribute_to_string(attr))); - } - - write!(out, "\n\n") -} - -pub fn get_crate_attributes(data: &[u8]) -> Vec { - get_attributes(rbml::Doc::new(data)) -} - -#[derive(Clone)] -pub struct CrateDep { - pub cnum: ast::CrateNum, - pub name: String, - pub hash: Svh, - pub explicitly_linked: bool, -} - -pub fn get_crate_deps(data: &[u8]) -> Vec { - let cratedoc = rbml::Doc::new(data); - let depsdoc = reader::get_doc(cratedoc, tag_crate_deps); - - fn docstr(doc: rbml::Doc, tag_: usize) -> String { - let d = reader::get_doc(doc, tag_); - d.as_str_slice().to_string() - } - - reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { - let name = docstr(depdoc, tag_crate_dep_crate_name); - let hash = Svh::new(&docstr(depdoc, tag_crate_dep_hash)); - let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked); - let explicitly_linked = reader::doc_as_u8(doc) != 0; - CrateDep { - cnum: crate_num as u32 + 1, - name: name, - hash: hash, - explicitly_linked: explicitly_linked, - } - }).collect() -} - -fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { - try!(write!(out, "=External Dependencies=\n")); - for dep in &get_crate_deps(data) { - try!(write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash)); - } - try!(write!(out, "\n")); - Ok(()) -} - -pub fn maybe_get_crate_hash(data: &[u8]) -> Option { - let cratedoc = rbml::Doc::new(data); - reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { - Svh::new(doc.as_str_slice()) - }) -} - -pub fn get_crate_hash(data: &[u8]) -> Svh { - let cratedoc = rbml::Doc::new(data); - let hashdoc = reader::get_doc(cratedoc, tag_crate_hash); - Svh::new(hashdoc.as_str_slice()) -} - -pub fn maybe_get_crate_name(data: &[u8]) -> Option { - let cratedoc = rbml::Doc::new(data); - reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| { - doc.as_str_slice().to_string() - }) -} - -pub fn get_crate_triple(data: &[u8]) -> Option { - let cratedoc = rbml::Doc::new(data); - let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple); - triple_doc.map(|s| s.as_str().to_string()) -} - -pub fn get_crate_name(data: &[u8]) -> String { - maybe_get_crate_name(data).expect("no crate name in crate") -} - -pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> { - let hash = get_crate_hash(bytes); - let md = rbml::Doc::new(bytes); - try!(list_crate_attributes(md, &hash, out)); - list_crate_deps(bytes, out) -} - -// Translates a def_id from an external crate to a def_id for the current -// compilation environment. We use this when trying to load types from -// external crates - if those types further refer to types in other crates -// then we must translate the crate number from that encoded in the external -// crate to the correct local crate number. -pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId { - if did.is_local() { - return DefId { krate: cdata.cnum, index: did.index }; - } - - match cdata.cnum_map.borrow().get(&did.krate) { - Some(&n) => { - DefId { - krate: n, - index: did.index, - } - } - None => panic!("didn't find a crate in the cnum_map") - } -} - -// Translate a DefId from the current compilation environment to a DefId -// for an external crate. -fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { - if did.krate == cdata.cnum { - return Some(DefId { krate: LOCAL_CRATE, index: did.index }); - } - - for (&local, &global) in cdata.cnum_map.borrow().iter() { - if global == did.krate { - return Some(DefId { krate: local, index: did.index }); - } - } - - None -} - -pub fn each_inherent_implementation_for_type(cdata: Cmd, - id: DefIndex, - mut callback: F) - where F: FnMut(DefId), -{ - let item_doc = cdata.lookup_item(id); - for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) { - if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() { - callback(item_def_id(impl_doc, cdata)); - } - } -} - -pub fn each_implementation_for_trait(cdata: Cmd, - def_id: DefId, - mut callback: F) where - F: FnMut(DefId), -{ - // Do a reverse lookup beforehand to avoid touching the crate_num - // hash map in the loop below. - if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) { - let def_id_u64 = def_to_u64(crate_local_did); - - let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls); - for trait_doc in reader::tagged_docs(impls_doc, tag_impls_trait) { - let trait_def_id = reader::get_doc(trait_doc, tag_def_id); - if reader::doc_as_u64(trait_def_id) != def_id_u64 { - continue; - } - for impl_doc in reader::tagged_docs(trait_doc, tag_impls_trait_impl) { - callback(translated_def_id(cdata, impl_doc)); - } - } - } -} - -pub fn get_trait_of_item(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) - -> Option { - let item_doc = cdata.lookup_item(id); - let parent_item_id = match item_parent_item(cdata, item_doc) { - None => return None, - Some(item_id) => item_id, - }; - let parent_item_doc = cdata.lookup_item(parent_item_id.index); - match item_family(parent_item_doc) { - Trait => Some(item_def_id(parent_item_doc, cdata)), - Impl | DefaultImpl => { - reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref) - .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id) - } - _ => None - } -} - - -pub fn get_native_libraries(cdata: Cmd) - -> Vec<(cstore::NativeLibraryKind, String)> { - let libraries = reader::get_doc(rbml::Doc::new(cdata.data()), - tag_native_libraries); - reader::tagged_docs(libraries, tag_native_libraries_lib).map(|lib_doc| { - let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind); - let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name); - let kind: cstore::NativeLibraryKind = - cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap(); - let name = name_doc.as_str().to_string(); - (kind, name) - }).collect() -} - -pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { - reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn) - .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc))) -} - -pub fn each_exported_macro(data: &[u8], intr: &IdentInterner, mut f: F) where - F: FnMut(ast::Name, Vec, String) -> bool, -{ - let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs); - for macro_doc in reader::tagged_docs(macros, tag_macro_def) { - let name = item_name(intr, macro_doc); - let attrs = get_attributes(macro_doc); - let body = reader::get_doc(macro_doc, tag_macro_def_body); - if !f(name, attrs, body.as_str().to_string()) { - break; - } - } -} - -pub fn get_dylib_dependency_formats(cdata: Cmd) - -> Vec<(ast::CrateNum, cstore::LinkagePreference)> -{ - let formats = reader::get_doc(rbml::Doc::new(cdata.data()), - tag_dylib_dependency_formats); - let mut result = Vec::new(); - - debug!("found dylib deps: {}", formats.as_str_slice()); - for spec in formats.as_str_slice().split(',') { - if spec.is_empty() { continue } - let cnum = spec.split(':').nth(0).unwrap(); - let link = spec.split(':').nth(1).unwrap(); - let cnum: ast::CrateNum = cnum.parse().unwrap(); - let cnum = match cdata.cnum_map.borrow().get(&cnum) { - Some(&n) => n, - None => panic!("didn't find a crate in the cnum_map") - }; - result.push((cnum, if link == "d" { - cstore::RequireDynamic - } else { - cstore::RequireStatic - })); - } - return result; -} - -pub fn get_missing_lang_items(cdata: Cmd) - -> Vec -{ - let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_lang_items); - reader::tagged_docs(items, tag_lang_items_missing).map(|missing_docs| { - lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap() - }).collect() -} - -pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { - let method_doc = cdata.lookup_item(id); - match reader::maybe_get_doc(method_doc, tag_method_argument_names) { - Some(args_doc) => { - reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| { - name_doc.as_str_slice().to_string() - }).collect() - }, - None => vec![], - } -} - -pub fn get_reachable_ids(cdata: Cmd) -> Vec { - let items = reader::get_doc(rbml::Doc::new(cdata.data()), - tag_reachable_ids); - reader::tagged_docs(items, tag_reachable_id).map(|doc| { - DefId { - krate: cdata.cnum, - index: DefIndex::from_u32(reader::doc_as_u32(doc)), - } - }).collect() -} - -pub fn is_typedef(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - match item_family(item_doc) { - Type => true, - _ => false, - } -} - -pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - match fn_constness(item_doc) { - hir::Constness::Const => true, - hir::Constness::NotConst => false, - } -} - -pub fn is_static(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - match item_family(item_doc) { - ImmStatic | MutStatic => true, - _ => false, - } -} - -pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - match item_family(item_doc) { - Impl => true, - _ => false, - } -} - -fn doc_generics<'tcx>(base_doc: rbml::Doc, - tcx: &ty::ctxt<'tcx>, - cdata: Cmd, - tag: usize) - -> ty::Generics<'tcx> -{ - let doc = reader::get_doc(base_doc, tag); - - let mut types = subst::VecPerParamSpace::empty(); - for p in reader::tagged_docs(doc, tag_type_param_def) { - let bd = - TyDecoder::with_doc(tcx, cdata.cnum, p, - &mut |did| translate_def_id(cdata, did)) - .parse_type_param_def(); - types.push(bd.space, bd); - } - - let mut regions = subst::VecPerParamSpace::empty(); - for rp_doc in reader::tagged_docs(doc, tag_region_param_def) { - let ident_str_doc = reader::get_doc(rp_doc, - tag_region_param_def_ident); - let name = item_name(&*token::get_ident_interner(), ident_str_doc); - let def_id_doc = reader::get_doc(rp_doc, - tag_region_param_def_def_id); - let def_id = translated_def_id(cdata, def_id_doc); - - let doc = reader::get_doc(rp_doc, tag_region_param_def_space); - let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as usize); - - let doc = reader::get_doc(rp_doc, tag_region_param_def_index); - let index = reader::doc_as_u64(doc) as u32; - - let bounds = reader::tagged_docs(rp_doc, tag_items_data_region).map(|p| { - TyDecoder::with_doc(tcx, cdata.cnum, p, - &mut |did| translate_def_id(cdata, did)) - .parse_region() - }).collect(); - - regions.push(space, ty::RegionParameterDef { name: name, - def_id: def_id, - space: space, - index: index, - bounds: bounds }); - } - - ty::Generics { types: types, regions: regions } -} - -fn doc_predicate<'tcx>(cdata: Cmd, - doc: rbml::Doc, - tcx: &ty::ctxt<'tcx>) - -> ty::Predicate<'tcx> -{ - let predicate_pos = cdata.xref_index.lookup( - cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize; - TyDecoder::new( - cdata.data(), cdata.cnum, predicate_pos, tcx, - &mut |did| translate_def_id(cdata, did) - ).parse_predicate() -} - -fn doc_predicates<'tcx>(base_doc: rbml::Doc, - tcx: &ty::ctxt<'tcx>, - cdata: Cmd, - tag: usize) - -> ty::GenericPredicates<'tcx> -{ - let doc = reader::get_doc(base_doc, tag); - - let mut predicates = subst::VecPerParamSpace::empty(); - for predicate_doc in reader::tagged_docs(doc, tag_type_predicate) { - predicates.push(subst::TypeSpace, - doc_predicate(cdata, predicate_doc, tcx)); - } - for predicate_doc in reader::tagged_docs(doc, tag_self_predicate) { - predicates.push(subst::SelfSpace, - doc_predicate(cdata, predicate_doc, tcx)); - } - for predicate_doc in reader::tagged_docs(doc, tag_fn_predicate) { - predicates.push(subst::FnSpace, - doc_predicate(cdata, predicate_doc, tcx)); - } - - ty::GenericPredicates { predicates: predicates } -} - -pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool { - let trait_doc = cdata.lookup_item(trait_id); - assert!(item_family(trait_doc) == Family::Trait); - let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait); - reader::doc_as_u8(defaulted_doc) != 0 -} - -pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool { - let impl_doc = cdata.lookup_item(impl_id); - item_family(impl_doc) == Family::DefaultImpl -} - -pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { - let crate_doc = rbml::Doc::new(metadata); - let cm_doc = reader::get_doc(crate_doc, tag_codemap); - - reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| { - let mut decoder = reader::Decoder::new(filemap_doc); - Decodable::decode(&mut decoder).unwrap() - }).collect() -} - -pub fn is_extern_fn(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) -> bool { - let item_doc = match cdata.get_item(id) { - Some(doc) => doc, - None => return false, - }; - if let Fn = item_family(item_doc) { - let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx); - generics.types.is_empty() && match ty.sty { - ty::TyBareFn(_, fn_ty) => fn_ty.abi != abi::Rust, - _ => false, - } - } else { - false - } -} - -pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { - let closure_doc = cdata.lookup_item(closure_id); - let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind); - let mut decoder = reader::Decoder::new(closure_kind_doc); - ty::ClosureKind::decode(&mut decoder).unwrap() -} - -pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &ty::ctxt<'tcx>) - -> ty::ClosureTy<'tcx> { - let closure_doc = cdata.lookup_item(closure_id); - let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty); - TyDecoder::with_doc(tcx, cdata.cnum, closure_ty_doc, &mut |did| translate_def_id(cdata, did)) - .parse_closure_ty() -} - -fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey { - match reader::maybe_get_doc(item_doc, tag_def_key) { - Some(def_key_doc) => { - let mut decoder = reader::Decoder::new(def_key_doc); - hir_map::DefKey::decode(&mut decoder).unwrap() - } - None => { - panic!("failed to find block with tag {:?} for item with family {:?}", - tag_def_key, - item_family(item_doc)) - } - } -} - -pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath { - debug!("def_path(id={:?})", id); - hir_map::definitions::make_def_path(id, |parent| { - debug!("def_path: parent={:?}", parent); - let parent_doc = cdata.lookup_item(parent); - def_key(parent_doc) - }) -} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs deleted file mode 100644 index d86d6c25cce..00000000000 --- a/src/librustc/metadata/encoder.rs +++ /dev/null @@ -1,2078 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Metadata encoding - -#![allow(unused_must_use)] // everything is just a MemWriter, can't fail -#![allow(non_camel_case_types)] - -use back::svh::Svh; -use session::config; -use metadata::common::*; -use metadata::cstore; -use metadata::cstore::LOCAL_CRATE; -use metadata::decoder; -use metadata::tyencode; -use metadata::index::{self, IndexData}; -use metadata::inline::InlinedItemRef; -use metadata::util::CrateStore; -use middle::def; -use middle::def_id::{CRATE_DEF_INDEX, DefId}; -use middle::dependency_format::Linkage; -use middle::stability; -use middle::subst; -use middle::ty::{self, Ty}; -use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; - -use serialize::Encodable; -use std::cell::RefCell; -use std::io::prelude::*; -use std::io::{Cursor, SeekFrom}; -use std::rc::Rc; -use std::u32; -use syntax::abi; -use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; -use syntax::attr; -use syntax::attr::AttrMetaMethods; -use syntax::diagnostic::SpanHandler; -use syntax::parse::token::special_idents; -use syntax; -use rbml::writer::Encoder; - -use rustc_front::hir; -use rustc_front::intravisit::Visitor; -use rustc_front::intravisit; -use front::map::{LinkedPath, PathElem, PathElems}; -use front::map as ast_map; - -pub type EncodeInlinedItem<'a> = - Box; - -pub struct EncodeParams<'a, 'tcx: 'a> { - pub diag: &'a SpanHandler, - pub tcx: &'a ty::ctxt<'tcx>, - pub reexports: &'a def::ExportMap, - pub item_symbols: &'a RefCell>, - pub link_meta: &'a LinkMeta, - pub cstore: &'a cstore::CStore, - pub encode_inlined_item: EncodeInlinedItem<'a>, - pub reachable: &'a NodeSet, -} - -pub struct EncodeContext<'a, 'tcx: 'a> { - pub diag: &'a SpanHandler, - pub tcx: &'a ty::ctxt<'tcx>, - pub reexports: &'a def::ExportMap, - pub item_symbols: &'a RefCell>, - pub link_meta: &'a LinkMeta, - pub cstore: &'a cstore::CStore, - pub encode_inlined_item: RefCell>, - pub type_abbrevs: tyencode::abbrev_map<'tcx>, - pub reachable: &'a NodeSet, -} - -impl<'a, 'tcx> EncodeContext<'a,'tcx> { - fn local_id(&self, def_id: DefId) -> NodeId { - self.tcx.map.as_local_node_id(def_id).unwrap() - } -} - -/// "interned" entries referenced by id -#[derive(PartialEq, Eq, Hash)] -pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } - -struct CrateIndex<'tcx> { - items: IndexData, - xrefs: FnvHashMap, u32>, // sequentially-assigned -} - -impl<'tcx> CrateIndex<'tcx> { - fn record(&mut self, id: DefId, rbml_w: &mut Encoder) { - let position = rbml_w.mark_stable_position(); - self.items.record(id, position); - } - - fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { - let old_len = self.xrefs.len() as u32; - *self.xrefs.entry(xref).or_insert(old_len) - } -} - -fn encode_name(rbml_w: &mut Encoder, name: Name) { - rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str()); -} - -fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id)); -} - -/// For every DefId that we create a metadata item for, we include a -/// serialized copy of its DefKey, which allows us to recreate a path. -fn encode_def_id_and_key(ecx: &EncodeContext, - rbml_w: &mut Encoder, - def_id: DefId) -{ - encode_def_id(rbml_w, def_id); - encode_def_key(ecx, rbml_w, def_id); -} - -fn encode_def_key(ecx: &EncodeContext, - rbml_w: &mut Encoder, - def_id: DefId) -{ - rbml_w.start_tag(tag_def_key); - let def_key = ecx.tcx.map.def_key(def_id); - def_key.encode(rbml_w); - rbml_w.end_tag(); -} - -fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - trait_ref: ty::TraitRef<'tcx>, - tag: usize) { - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - - rbml_w.start_tag(tag); - tyencode::enc_trait_ref(rbml_w, ty_str_ctxt, trait_ref); - rbml_w.end_tag(); -} - -// Item info table encoding -fn encode_family(rbml_w: &mut Encoder, c: char) { - rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8); -} - -pub fn def_to_u64(did: DefId) -> u64 { - assert!(did.index.as_u32() < u32::MAX); - (did.krate as u64) << 32 | (did.index.as_usize() as u64) -} - -pub fn def_to_string(did: DefId) -> String { - format!("{}:{}", did.krate, did.index.as_usize()) -} - -fn encode_item_variances(rbml_w: &mut Encoder, - ecx: &EncodeContext, - id: NodeId) { - let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id)); - rbml_w.start_tag(tag_item_variances); - v.encode(rbml_w); - rbml_w.end_tag(); -} - -fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, - id: NodeId) { - encode_bounds_and_type(rbml_w, - ecx, - index, - &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)), - &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id))); -} - -fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, - scheme: &ty::TypeScheme<'tcx>, - predicates: &ty::GenericPredicates<'tcx>) { - encode_generics(rbml_w, ecx, index, - &scheme.generics, &predicates, tag_item_generics); - encode_type(ecx, rbml_w, scheme.ty); -} - -fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) { - let id = def_to_u64(vid); - rbml_w.wr_tagged_u64(tag_items_data_item_variant, id); - rbml_w.wr_tagged_u64(tag_mod_child, id); -} - -pub fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - closure_type: &ty::ClosureTy<'tcx>) { - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - tyencode::enc_closure_ty(rbml_w, ty_str_ctxt, closure_type); -} - -pub fn write_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - typ: Ty<'tcx>) { - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - tyencode::enc_ty(rbml_w, ty_str_ctxt, typ); -} - -pub fn write_trait_ref<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - trait_ref: &ty::TraitRef<'tcx>) { - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - tyencode::enc_trait_ref(rbml_w, ty_str_ctxt, *trait_ref); -} - -pub fn write_region(ecx: &EncodeContext, - rbml_w: &mut Encoder, - r: ty::Region) { - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - tyencode::enc_region(rbml_w, ty_str_ctxt, r); -} - -fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - typ: Ty<'tcx>) { - rbml_w.start_tag(tag_items_data_item_type); - write_type(ecx, rbml_w, typ); - rbml_w.end_tag(); -} - -fn encode_region(ecx: &EncodeContext, - rbml_w: &mut Encoder, - r: ty::Region) { - rbml_w.start_tag(tag_items_data_region); - write_region(ecx, rbml_w, r); - rbml_w.end_tag(); -} - -fn encode_symbol(ecx: &EncodeContext, - rbml_w: &mut Encoder, - id: NodeId) { - match ecx.item_symbols.borrow().get(&id) { - Some(x) => { - debug!("encode_symbol(id={}, str={})", id, *x); - rbml_w.wr_tagged_str(tag_items_data_item_symbol, x); - } - None => { - ecx.diag.handler().bug( - &format!("encode_symbol: id not found {}", id)); - } - } -} - -fn encode_disr_val(_: &EncodeContext, - rbml_w: &mut Encoder, - disr_val: ty::Disr) { - rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_string()); -} - -fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); -} - -fn encode_struct_fields(rbml_w: &mut Encoder, - variant: ty::VariantDef) { - for f in &variant.fields { - if f.name == special_idents::unnamed_field.name { - rbml_w.start_tag(tag_item_unnamed_field); - } else { - rbml_w.start_tag(tag_item_field); - encode_name(rbml_w, f.name); - } - encode_struct_field_family(rbml_w, f.vis); - encode_def_id(rbml_w, f.did); - rbml_w.end_tag(); - } -} - -fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - id: NodeId, - vis: hir::Visibility, - index: &mut CrateIndex<'tcx>) { - debug!("encode_enum_variant_info(id={})", id); - - let mut disr_val = 0; - let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id)); - for variant in &def.variants { - let vid = variant.did; - let variant_node_id = ecx.local_id(vid); - - if let ty::VariantKind::Struct = variant.kind() { - // tuple-like enum variant fields aren't really items so - // don't try to encode them. - for field in &variant.fields { - encode_field(ecx, rbml_w, field, index); - } - } - - index.record(vid, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, vid); - encode_family(rbml_w, match variant.kind() { - ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v', - ty::VariantKind::Struct => 'V' - }); - encode_name(rbml_w, variant.name); - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id)); - encode_visibility(rbml_w, vis); - - let attrs = ecx.tcx.get_attrs(vid); - encode_attributes(rbml_w, &attrs); - encode_repr_attrs(rbml_w, ecx, &attrs); - - let stab = stability::lookup(ecx.tcx, vid); - encode_stability(rbml_w, stab); - - encode_struct_fields(rbml_w, variant); - - let specified_disr_val = variant.disr_val; - if specified_disr_val != disr_val { - encode_disr_val(ecx, rbml_w, specified_disr_val); - disr_val = specified_disr_val; - } - encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id); - - ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path)); - rbml_w.end_tag(); - disr_val = disr_val.wrapping_add(1); - } -} - -fn encode_path>(rbml_w: &mut Encoder, path: PI) { - let path = path.collect::>(); - rbml_w.start_tag(tag_path); - rbml_w.wr_tagged_u32(tag_path_len, path.len() as u32); - for pe in &path { - let tag = match *pe { - ast_map::PathMod(_) => tag_path_elem_mod, - ast_map::PathName(_) => tag_path_elem_name - }; - rbml_w.wr_tagged_str(tag, &pe.name().as_str()); - } - rbml_w.end_tag(); -} - -/// Iterates through "auxiliary node IDs", which are node IDs that describe -/// top-level items that are sub-items of the given item. Specifically: -/// -/// * For newtype structs, iterates through the node ID of the constructor. -fn each_auxiliary_node_id(item: &hir::Item, callback: F) -> bool where - F: FnOnce(NodeId) -> bool, -{ - let mut continue_ = true; - match item.node { - hir::ItemStruct(ref struct_def, _) => { - // If this is a newtype struct, return the constructor. - if struct_def.is_tuple() { - continue_ = callback(struct_def.id()); - } - } - _ => {} - } - - continue_ -} - -fn encode_reexports(ecx: &EncodeContext, - rbml_w: &mut Encoder, - id: NodeId) { - debug!("(encoding info for module) encoding reexports for {}", id); - match ecx.reexports.get(&id) { - Some(exports) => { - debug!("(encoding info for module) found reexports for {}", id); - for exp in exports { - debug!("(encoding info for module) reexport '{}' ({:?}) for \ - {}", - exp.name, - exp.def_id, - id); - rbml_w.start_tag(tag_items_data_item_reexport); - rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, - def_to_u64(exp.def_id)); - rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, - &exp.name.as_str()); - rbml_w.end_tag(); - } - }, - None => debug!("(encoding info for module) found no reexports for {}", id), - } -} - -fn encode_info_for_mod(ecx: &EncodeContext, - rbml_w: &mut Encoder, - md: &hir::Mod, - attrs: &[ast::Attribute], - id: NodeId, - path: PathElems, - name: Name, - vis: hir::Visibility) { - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id)); - encode_family(rbml_w, 'm'); - encode_name(rbml_w, name); - debug!("(encoding info for module) encoding info for module ID {}", id); - - // Encode info about all the module children. - for item_id in &md.item_ids { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); - - let item = ecx.tcx.map.expect_item(item_id.id); - each_auxiliary_node_id(item, |auxiliary_node_id| { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); - true - }); - } - - encode_path(rbml_w, path.clone()); - encode_visibility(rbml_w, vis); - - let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(id)); - encode_stability(rbml_w, stab); - - // Encode the reexports of this module, if this module is public. - if vis == hir::Public { - debug!("(encoding info for module) encoding reexports for {}", id); - encode_reexports(ecx, rbml_w, id); - } - encode_attributes(rbml_w, attrs); - - rbml_w.end_tag(); -} - -fn encode_struct_field_family(rbml_w: &mut Encoder, - visibility: hir::Visibility) { - encode_family(rbml_w, match visibility { - hir::Public => 'g', - hir::Inherited => 'N' - }); -} - -fn encode_visibility(rbml_w: &mut Encoder, visibility: hir::Visibility) { - let ch = match visibility { - hir::Public => 'y', - hir::Inherited => 'i', - }; - rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); -} - -fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) { - rbml_w.start_tag(tag_items_data_item_constness); - let ch = match constness { - hir::Constness::Const => 'c', - hir::Constness::NotConst => 'n', - }; - rbml_w.wr_str(&ch.to_string()); - rbml_w.end_tag(); -} - -fn encode_explicit_self(rbml_w: &mut Encoder, - explicit_self: &ty::ExplicitSelfCategory) { - let tag = tag_item_trait_method_explicit_self; - - // Encode the base self type. - match *explicit_self { - ty::StaticExplicitSelfCategory => { - rbml_w.wr_tagged_bytes(tag, &['s' as u8]); - } - ty::ByValueExplicitSelfCategory => { - rbml_w.wr_tagged_bytes(tag, &['v' as u8]); - } - ty::ByBoxExplicitSelfCategory => { - rbml_w.wr_tagged_bytes(tag, &['~' as u8]); - } - ty::ByReferenceExplicitSelfCategory(_, m) => { - // FIXME(#4846) encode custom lifetime - let ch = encode_mutability(m); - rbml_w.wr_tagged_bytes(tag, &['&' as u8, ch]); - } - } - - fn encode_mutability(m: hir::Mutability) -> u8 { - match m { - hir::MutImmutable => 'i' as u8, - hir::MutMutable => 'm' as u8, - } - } -} - -fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { - rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8); -} - -fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - field: ty::FieldDef<'tcx>, - index: &mut CrateIndex<'tcx>) { - let nm = field.name; - let id = ecx.local_id(field.did); - - index.record(field.did, rbml_w); - rbml_w.start_tag(tag_items_data_item); - debug!("encode_field: encoding {} {}", nm, id); - encode_struct_field_family(rbml_w, field.vis); - encode_name(rbml_w, nm); - encode_bounds_and_type_for_item(rbml_w, ecx, index, id); - encode_def_id_and_key(ecx, rbml_w, field.did); - - let stab = stability::lookup(ecx.tcx, field.did); - encode_stability(rbml_w, stab); - - rbml_w.end_tag(); -} - -fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - name: Name, - ctor_id: NodeId, - index: &mut CrateIndex<'tcx>, - struct_id: NodeId) { - let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); - - index.record(ctor_def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, ctor_def_id); - encode_family(rbml_w, 'o'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id); - encode_name(rbml_w, name); - ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path)); - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); - - if ecx.item_symbols.borrow().contains_key(&ctor_id) { - encode_symbol(ecx, rbml_w, ctor_id); - } - - let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(ctor_id)); - encode_stability(rbml_w, stab); - - // indicate that this is a tuple struct ctor, because downstream users will normally want - // the tuple struct definition, but without this there is no way for them to tell that - // they actually have a ctor rather than a normal function - rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); - - rbml_w.end_tag(); -} - -fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, - generics: &ty::Generics<'tcx>, - predicates: &ty::GenericPredicates<'tcx>, - tag: usize) -{ - rbml_w.start_tag(tag); - - // Type parameters - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - - for param in &generics.types { - rbml_w.start_tag(tag_type_param_def); - tyencode::enc_type_param_def(rbml_w, ty_str_ctxt, param); - rbml_w.end_tag(); - } - - // Region parameters - for param in &generics.regions { - rbml_w.start_tag(tag_region_param_def); - - rbml_w.start_tag(tag_region_param_def_ident); - encode_name(rbml_w, param.name); - rbml_w.end_tag(); - - rbml_w.wr_tagged_u64(tag_region_param_def_def_id, - def_to_u64(param.def_id)); - - rbml_w.wr_tagged_u64(tag_region_param_def_space, - param.space.to_uint() as u64); - - rbml_w.wr_tagged_u64(tag_region_param_def_index, - param.index as u64); - - for &bound_region in ¶m.bounds { - encode_region(ecx, rbml_w, bound_region); - } - - rbml_w.end_tag(); - } - - encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); - - rbml_w.end_tag(); -} - -fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, - _ecx: &EncodeContext<'a,'tcx>, - index: &mut CrateIndex<'tcx>, - predicates: &ty::GenericPredicates<'tcx>) -{ - for (space, _, predicate) in predicates.predicates.iter_enumerated() { - let tag = match space { - subst::TypeSpace => tag_type_predicate, - subst::SelfSpace => tag_self_predicate, - subst::FnSpace => tag_fn_predicate - }; - - rbml_w.wr_tagged_u32(tag, - index.add_xref(XRef::Predicate(predicate.clone()))); - } -} - -fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a,'tcx>, - index: &mut CrateIndex<'tcx>, - predicates: &ty::GenericPredicates<'tcx>, - tag: usize) -{ - rbml_w.start_tag(tag); - encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); - rbml_w.end_tag(); -} - -fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, - method_ty: &ty::Method<'tcx>) { - encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); - encode_name(rbml_w, method_ty.name); - encode_generics(rbml_w, ecx, index, - &method_ty.generics, &method_ty.predicates, - tag_method_ty_generics); - encode_visibility(rbml_w, method_ty.vis); - encode_explicit_self(rbml_w, &method_ty.explicit_self); - match method_ty.explicit_self { - ty::StaticExplicitSelfCategory => { - encode_family(rbml_w, STATIC_METHOD_FAMILY); - } - _ => encode_family(rbml_w, METHOD_FAMILY) - } -} - -fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, - associated_const: &ty::AssociatedConst, - impl_path: PathElems, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - debug!("encode_info_for_associated_const({:?},{:?})", - associated_const.def_id, - associated_const.name); - - index.record(associated_const.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); - encode_name(rbml_w, associated_const.name); - encode_visibility(rbml_w, associated_const.vis); - encode_family(rbml_w, 'C'); - - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 'C'); - - encode_bounds_and_type_for_item(rbml_w, ecx, index, - ecx.local_id(associated_const.def_id)); - - let stab = stability::lookup(ecx.tcx, associated_const.def_id); - encode_stability(rbml_w, stab); - - let elem = ast_map::PathName(associated_const.name); - encode_path(rbml_w, impl_path.chain(Some(elem))); - - if let Some(ii) = impl_item_opt { - encode_attributes(rbml_w, &ii.attrs); - encode_inlined_item(ecx, - rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), - ii)); - } - - rbml_w.end_tag(); -} - -fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, - m: &ty::Method<'tcx>, - impl_path: PathElems, - is_default_impl: bool, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - - debug!("encode_info_for_method: {:?} {:?}", m.def_id, - m.name); - index.record(m.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_method_ty_fields(ecx, rbml_w, index, m); - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 'r'); - - let stab = stability::lookup(ecx.tcx, m.def_id); - encode_stability(rbml_w, stab); - - let m_node_id = ecx.local_id(m.def_id); - encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id); - - let elem = ast_map::PathName(m.name); - encode_path(rbml_w, impl_path.chain(Some(elem))); - if let Some(impl_item) = impl_item_opt { - if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - encode_attributes(rbml_w, &impl_item.attrs); - let scheme = ecx.tcx.lookup_item_type(m.def_id); - let any_types = !scheme.generics.types.is_empty(); - let needs_inline = any_types || is_default_impl || - attr::requests_inline(&impl_item.attrs); - if needs_inline || sig.constness == hir::Constness::Const { - encode_inlined_item(ecx, - rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), - impl_item)); - } - encode_constness(rbml_w, sig.constness); - if !any_types { - let m_id = ecx.local_id(m.def_id); - encode_symbol(ecx, rbml_w, m_id); - } - encode_method_argument_names(rbml_w, &sig.decl); - } - } - - rbml_w.end_tag(); -} - -fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, - associated_type: &ty::AssociatedType<'tcx>, - impl_path: PathElems, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - debug!("encode_info_for_associated_type({:?},{:?})", - associated_type.def_id, - associated_type.name); - - index.record(associated_type.def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); - encode_name(rbml_w, associated_type.name); - encode_visibility(rbml_w, associated_type.vis); - encode_family(rbml_w, 'y'); - encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(rbml_w, 't'); - - let stab = stability::lookup(ecx.tcx, associated_type.def_id); - encode_stability(rbml_w, stab); - - let elem = ast_map::PathName(associated_type.name); - encode_path(rbml_w, impl_path.chain(Some(elem))); - - if let Some(ii) = impl_item_opt { - encode_attributes(rbml_w, &ii.attrs); - } else { - encode_predicates(rbml_w, ecx, index, - &ecx.tcx.lookup_predicates(associated_type.def_id), - tag_item_generics); - } - - if let Some(ty) = associated_type.ty { - encode_type(ecx, rbml_w, ty); - } - - rbml_w.end_tag(); -} - -fn encode_method_argument_names(rbml_w: &mut Encoder, - decl: &hir::FnDecl) { - rbml_w.start_tag(tag_method_argument_names); - for arg in &decl.inputs { - let tag = tag_method_argument_name; - if let hir::PatIdent(_, ref path1, _) = arg.pat.node { - let name = path1.node.name.as_str(); - rbml_w.wr_tagged_bytes(tag, name.as_bytes()); - } else { - rbml_w.wr_tagged_bytes(tag, &[]); - } - } - rbml_w.end_tag(); -} - -fn encode_repr_attrs(rbml_w: &mut Encoder, - ecx: &EncodeContext, - attrs: &[ast::Attribute]) { - let mut repr_attrs = Vec::new(); - for attr in attrs { - repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(), - attr)); - } - rbml_w.start_tag(tag_items_data_item_repr); - repr_attrs.encode(rbml_w); - rbml_w.end_tag(); -} - -fn encode_inlined_item(ecx: &EncodeContext, - rbml_w: &mut Encoder, - ii: InlinedItemRef) { - let mut eii = ecx.encode_inlined_item.borrow_mut(); - let eii: &mut EncodeInlinedItem = &mut *eii; - eii(ecx, rbml_w, ii) -} - -const FN_FAMILY: char = 'f'; -const STATIC_METHOD_FAMILY: char = 'F'; -const METHOD_FAMILY: char = 'h'; - -// Encodes the inherent implementations of a structure, enumeration, or trait. -fn encode_inherent_implementations(ecx: &EncodeContext, - rbml_w: &mut Encoder, - def_id: DefId) { - match ecx.tcx.inherent_impls.borrow().get(&def_id) { - None => {} - Some(implementations) => { - for &impl_def_id in implementations.iter() { - rbml_w.start_tag(tag_items_data_item_inherent_impl); - encode_def_id(rbml_w, impl_def_id); - rbml_w.end_tag(); - } - } - } -} - -fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) { - stab_opt.map(|stab| { - rbml_w.start_tag(tag_items_data_item_stability); - stab.encode(rbml_w).unwrap(); - rbml_w.end_tag(); - }); -} - -fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - xrefs: FnvHashMap, u32>) -{ - let ty_str_ctxt = &tyencode::ctxt { - diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs - }; - - let mut xref_positions = vec![0; xrefs.len()]; - rbml_w.start_tag(tag_xref_data); - for (xref, id) in xrefs.into_iter() { - xref_positions[id as usize] = rbml_w.mark_stable_position() as u32; - match xref { - XRef::Predicate(p) => { - tyencode::enc_predicate(rbml_w, ty_str_ctxt, &p) - } - } - } - rbml_w.end_tag(); - - rbml_w.start_tag(tag_xref_index); - index::write_dense_index(xref_positions, rbml_w.writer); - rbml_w.end_tag(); -} - -fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - item: &hir::Item, - index: &mut CrateIndex<'tcx>, - path: PathElems, - vis: hir::Visibility) { - let tcx = ecx.tcx; - - debug!("encoding info for item at {}", - tcx.sess.codemap().span_to_string(item.span)); - - let def_id = ecx.tcx.map.local_def_id(item.id); - let stab = stability::lookup(tcx, ecx.tcx.map.local_def_id(item.id)); - - match item.node { - hir::ItemStatic(_, m, _) => { - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - if m == hir::MutMutable { - encode_family(rbml_w, 'b'); - } else { - encode_family(rbml_w, 'c'); - } - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_symbol(ecx, rbml_w, item.id); - encode_name(rbml_w, item.name); - encode_path(rbml_w, path); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_attributes(rbml_w, &item.attrs); - rbml_w.end_tag(); - } - hir::ItemConst(_, _) => { - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'C'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_path(rbml_w, path); - encode_attributes(rbml_w, &item.attrs); - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - rbml_w.end_tag(); - } - hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, FN_FAMILY); - let tps_len = generics.ty_params.len(); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_path(rbml_w, path); - encode_attributes(rbml_w, &item.attrs); - let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if needs_inline || constness == hir::Constness::Const { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); - } - if tps_len == 0 { - encode_symbol(ecx, rbml_w, item.id); - } - encode_constness(rbml_w, constness); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - encode_method_argument_names(rbml_w, &**decl); - rbml_w.end_tag(); - } - hir::ItemMod(ref m) => { - index.record(def_id, rbml_w); - encode_info_for_mod(ecx, - rbml_w, - m, - &item.attrs, - item.id, - path, - item.name, - item.vis); - } - hir::ItemForeignMod(ref fm) => { - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'n'); - encode_name(rbml_w, item.name); - encode_path(rbml_w, path); - - // Encode all the items in this module. - for foreign_item in &fm.items { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); - } - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - rbml_w.end_tag(); - } - hir::ItemTy(..) => { - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'y'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_path(rbml_w, path); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - rbml_w.end_tag(); - } - hir::ItemEnum(ref enum_definition, _) => { - index.record(def_id, rbml_w); - - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 't'); - encode_item_variances(rbml_w, ecx, item.id); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_repr_attrs(rbml_w, ecx, &item.attrs); - for v in &enum_definition.variants { - encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); - } - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); - encode_path(rbml_w, path); - - // Encode inherent implementations for this enumeration. - encode_inherent_implementations(ecx, rbml_w, def_id); - - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - rbml_w.end_tag(); - - encode_enum_variant_info(ecx, - rbml_w, - item.id, - vis, - index); - } - hir::ItemStruct(ref struct_def, _) => { - let def = ecx.tcx.lookup_adt_def(def_id); - let variant = def.struct_variant(); - - /* Index the class*/ - index.record(def_id, rbml_w); - - /* Now, make an item for the class itself */ - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'S'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - - encode_item_variances(rbml_w, ecx, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_path(rbml_w, path.clone()); - encode_stability(rbml_w, stab); - encode_visibility(rbml_w, vis); - encode_repr_attrs(rbml_w, ecx, &item.attrs); - - /* Encode def_ids for each field and method - for methods, write all the stuff get_trait_method - needs to know*/ - encode_struct_fields(rbml_w, variant); - - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); - - // Encode inherent implementations for this structure. - encode_inherent_implementations(ecx, rbml_w, def_id); - - if !struct_def.is_struct() { - let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); - rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, - def_to_u64(ctor_did)); - } - - rbml_w.end_tag(); - - for field in &variant.fields { - encode_field(ecx, rbml_w, field, index); - } - - // If this is a tuple-like struct, encode the type of the constructor. - if !struct_def.is_struct() { - encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id); - } - } - hir::ItemDefaultImpl(unsafety, _) => { - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'd'); - encode_name(rbml_w, item.name); - encode_unsafety(rbml_w, unsafety); - - let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); - encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); - rbml_w.end_tag(); - } - hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { - // We need to encode information about the default methods we - // have inherited, so we drive this based on the impl structure. - let impl_items = tcx.impl_items.borrow(); - let items = impl_items.get(&def_id).unwrap(); - - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'i'); - encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_unsafety(rbml_w, unsafety); - encode_polarity(rbml_w, polarity); - - match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) { - Some(&kind) => { - rbml_w.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(rbml_w); - rbml_w.end_tag(); - } - None => {} - } - - for &item_def_id in items { - rbml_w.start_tag(tag_item_impl_item); - match item_def_id { - ty::ConstTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 'C'); - } - ty::MethodTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 'r'); - } - ty::TypeTraitItemId(item_def_id) => { - encode_def_id(rbml_w, item_def_id); - encode_item_sort(rbml_w, 't'); - } - } - rbml_w.end_tag(); - } - if let Some(trait_ref) = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)) { - encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); - } - encode_path(rbml_w, path.clone()); - encode_stability(rbml_w, stab); - rbml_w.end_tag(); - - // Iterate down the trait items, emitting them. We rely on the - // assumption that all of the actually implemented trait items - // appear first in the impl structure, in the same order they do - // in the ast. This is a little sketchy. - let num_implemented_methods = ast_items.len(); - for (i, &trait_item_def_id) in items.iter().enumerate() { - let ast_item = if i < num_implemented_methods { - Some(&*ast_items[i]) - } else { - None - }; - - match tcx.impl_or_trait_item(trait_item_def_id.def_id()) { - ty::ConstTraitItem(ref associated_const) => { - encode_info_for_associated_const(ecx, - rbml_w, - index, - &*associated_const, - path.clone(), - item.id, - ast_item) - } - ty::MethodTraitItem(ref method_type) => { - encode_info_for_method(ecx, - rbml_w, - index, - &**method_type, - path.clone(), - false, - item.id, - ast_item) - } - ty::TypeTraitItem(ref associated_type) => { - encode_info_for_associated_type(ecx, - rbml_w, - index, - &**associated_type, - path.clone(), - item.id, - ast_item) - } - } - } - } - hir::ItemTrait(_, _, _, ref ms) => { - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_family(rbml_w, 'I'); - encode_item_variances(rbml_w, ecx, item.id); - let trait_def = tcx.lookup_trait_def(def_id); - let trait_predicates = tcx.lookup_predicates(def_id); - encode_unsafety(rbml_w, trait_def.unsafety); - encode_paren_sugar(rbml_w, trait_def.paren_sugar); - encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); - encode_associated_type_names(rbml_w, &trait_def.associated_type_names); - encode_generics(rbml_w, ecx, index, - &trait_def.generics, &trait_predicates, - tag_item_generics); - encode_predicates(rbml_w, ecx, index, - &tcx.lookup_super_predicates(def_id), - tag_item_super_predicates); - encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); - encode_name(rbml_w, item.name); - encode_attributes(rbml_w, &item.attrs); - encode_visibility(rbml_w, vis); - encode_stability(rbml_w, stab); - for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { - rbml_w.start_tag(tag_item_trait_item); - match method_def_id { - ty::ConstTraitItemId(const_def_id) => { - encode_def_id(rbml_w, const_def_id); - encode_item_sort(rbml_w, 'C'); - } - ty::MethodTraitItemId(method_def_id) => { - encode_def_id(rbml_w, method_def_id); - encode_item_sort(rbml_w, 'r'); - } - ty::TypeTraitItemId(type_def_id) => { - encode_def_id(rbml_w, type_def_id); - encode_item_sort(rbml_w, 't'); - } - } - rbml_w.end_tag(); - - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(method_def_id.def_id())); - } - encode_path(rbml_w, path.clone()); - - // Encode inherent implementations for this trait. - encode_inherent_implementations(ecx, rbml_w, def_id); - - rbml_w.end_tag(); - - // Now output the trait item info for each trait item. - let r = tcx.trait_item_def_ids(def_id); - for (i, &item_def_id) in r.iter().enumerate() { - assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - - index.record(item_def_id.def_id(), rbml_w); - rbml_w.start_tag(tag_items_data_item); - - encode_parent_item(rbml_w, def_id); - - let stab = stability::lookup(tcx, item_def_id.def_id()); - encode_stability(rbml_w, stab); - - let trait_item_type = - tcx.impl_or_trait_item(item_def_id.def_id()); - let is_nonstatic_method; - match trait_item_type { - ty::ConstTraitItem(associated_const) => { - encode_name(rbml_w, associated_const.name); - encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); - encode_visibility(rbml_w, associated_const.vis); - - let elem = ast_map::PathName(associated_const.name); - encode_path(rbml_w, - path.clone().chain(Some(elem))); - - encode_family(rbml_w, 'C'); - - encode_bounds_and_type_for_item(rbml_w, ecx, index, - ecx.local_id(associated_const.def_id)); - - is_nonstatic_method = false; - } - ty::MethodTraitItem(method_ty) => { - let method_def_id = item_def_id.def_id(); - - encode_method_ty_fields(ecx, rbml_w, index, &*method_ty); - - let elem = ast_map::PathName(method_ty.name); - encode_path(rbml_w, - path.clone().chain(Some(elem))); - - match method_ty.explicit_self { - ty::StaticExplicitSelfCategory => { - encode_family(rbml_w, - STATIC_METHOD_FAMILY); - } - _ => { - encode_family(rbml_w, - METHOD_FAMILY); - } - } - encode_bounds_and_type_for_item(rbml_w, ecx, index, - ecx.local_id(method_def_id)); - - is_nonstatic_method = method_ty.explicit_self != - ty::StaticExplicitSelfCategory; - } - ty::TypeTraitItem(associated_type) => { - encode_name(rbml_w, associated_type.name); - encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); - - let elem = ast_map::PathName(associated_type.name); - encode_path(rbml_w, - path.clone().chain(Some(elem))); - - encode_item_sort(rbml_w, 't'); - encode_family(rbml_w, 'y'); - - if let Some(ty) = associated_type.ty { - encode_type(ecx, rbml_w, ty); - } - - is_nonstatic_method = false; - } - } - - let trait_item = &*ms[i]; - encode_attributes(rbml_w, &trait_item.attrs); - match trait_item.node { - hir::ConstTraitItem(_, ref default) => { - if default.is_some() { - encode_item_sort(rbml_w, 'C'); - } else { - encode_item_sort(rbml_w, 'c'); - } - - encode_inlined_item(ecx, rbml_w, - InlinedItemRef::TraitItem(def_id, trait_item)); - } - hir::MethodTraitItem(ref sig, ref body) => { - // If this is a static method, we've already - // encoded this. - if is_nonstatic_method { - // FIXME: I feel like there is something funny - // going on. - encode_bounds_and_type_for_item(rbml_w, ecx, index, - ecx.local_id(item_def_id.def_id())); - } - - if body.is_some() { - encode_item_sort(rbml_w, 'p'); - encode_inlined_item(ecx, rbml_w, - InlinedItemRef::TraitItem(def_id, trait_item)); - } else { - encode_item_sort(rbml_w, 'r'); - } - encode_method_argument_names(rbml_w, &sig.decl); - } - - hir::TypeTraitItem(..) => {} - } - - rbml_w.end_tag(); - } - } - hir::ItemExternCrate(_) | hir::ItemUse(_) => { - // these are encoded separately - } - } -} - -fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - nitem: &hir::ForeignItem, - index: &mut CrateIndex<'tcx>, - path: PathElems, - abi: abi::Abi) { - let def_id = ecx.tcx.map.local_def_id(nitem.id); - - index.record(def_id, rbml_w); - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - encode_visibility(rbml_w, nitem.vis); - match nitem.node { - hir::ForeignItemFn(ref fndecl, _) => { - encode_family(rbml_w, FN_FAMILY); - encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); - encode_name(rbml_w, nitem.name); - if abi == abi::RustIntrinsic || abi == abi::PlatformIntrinsic { - encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem)); - } - encode_attributes(rbml_w, &*nitem.attrs); - let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(rbml_w, stab); - encode_symbol(ecx, rbml_w, nitem.id); - encode_method_argument_names(rbml_w, &*fndecl); - } - hir::ForeignItemStatic(_, mutbl) => { - if mutbl { - encode_family(rbml_w, 'b'); - } else { - encode_family(rbml_w, 'c'); - } - encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); - encode_attributes(rbml_w, &*nitem.attrs); - let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(rbml_w, stab); - encode_symbol(ecx, rbml_w, nitem.id); - encode_name(rbml_w, nitem.name); - } - } - encode_path(rbml_w, path); - rbml_w.end_tag(); -} - -fn my_visit_expr(expr: &hir::Expr, - rbml_w: &mut Encoder, - ecx: &EncodeContext, - index: &mut CrateIndex) { - match expr.node { - hir::ExprClosure(..) => { - let def_id = ecx.tcx.map.local_def_id(expr.id); - - index.record(def_id, rbml_w); - - rbml_w.start_tag(tag_items_data_item); - encode_def_id_and_key(ecx, rbml_w, def_id); - - rbml_w.start_tag(tag_items_closure_ty); - write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); - rbml_w.end_tag(); - - rbml_w.start_tag(tag_items_closure_kind); - ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); - rbml_w.end_tag(); - - ecx.tcx.map.with_path(expr.id, |path| encode_path(rbml_w, path)); - - rbml_w.end_tag(); - } - _ => { } - } -} - -fn my_visit_item<'a, 'tcx>(i: &hir::Item, - rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>) { - ecx.tcx.map.with_path(i.id, |path| { - encode_info_for_item(ecx, rbml_w, i, index, path, i.vis); - }); -} - -fn my_visit_foreign_item<'a, 'tcx>(ni: &hir::ForeignItem, - rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>) { - debug!("writing foreign item {}::{}", - ecx.tcx.map.path_to_string(ni.id), - ni.name); - - let abi = ecx.tcx.map.get_foreign_abi(ni.id); - ecx.tcx.map.with_path(ni.id, |path| { - encode_info_for_foreign_item(ecx, rbml_w, - ni, index, - path, abi); - }); -} - -struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { - rbml_w_for_visit_item: &'a mut Encoder<'b>, - ecx: &'a EncodeContext<'c,'tcx>, - index: &'a mut CrateIndex<'tcx>, -} - -impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx hir::Expr) { - intravisit::walk_expr(self, ex); - my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index); - } - fn visit_item(&mut self, i: &'tcx hir::Item) { - intravisit::walk_item(self, i); - my_visit_item(i, self.rbml_w_for_visit_item, self.ecx, self.index); - } - fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { - intravisit::walk_foreign_item(self, ni); - my_visit_foreign_item(ni, self.rbml_w_for_visit_item, self.ecx, self.index); - } -} - -fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder) - -> CrateIndex<'tcx> { - let krate = ecx.tcx.map.krate(); - - let mut index = CrateIndex { - items: IndexData::new(ecx.tcx.map.num_local_def_ids()), - xrefs: FnvHashMap() - }; - rbml_w.start_tag(tag_items_data); - - index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); - encode_info_for_mod(ecx, - rbml_w, - &krate.module, - &[], - CRATE_NODE_ID, - [].iter().cloned().chain(LinkedPath::empty()), - syntax::parse::token::intern(&ecx.link_meta.crate_name), - hir::Public); - - krate.visit_all_items(&mut EncodeVisitor { - index: &mut index, - ecx: ecx, - rbml_w_for_visit_item: &mut *rbml_w, - }); - - rbml_w.end_tag(); - index -} - -fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { - rbml_w.start_tag(tag_index); - index.write_index(rbml_w.writer); - rbml_w.end_tag(); -} - -fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) { - match mi.node { - ast::MetaWord(ref name) => { - rbml_w.start_tag(tag_meta_item_word); - rbml_w.wr_tagged_str(tag_meta_item_name, name); - rbml_w.end_tag(); - } - ast::MetaNameValue(ref name, ref value) => { - match value.node { - ast::LitStr(ref value, _) => { - rbml_w.start_tag(tag_meta_item_name_value); - rbml_w.wr_tagged_str(tag_meta_item_name, name); - rbml_w.wr_tagged_str(tag_meta_item_value, value); - rbml_w.end_tag(); - } - _ => {/* FIXME (#623): encode other variants */ } - } - } - ast::MetaList(ref name, ref items) => { - rbml_w.start_tag(tag_meta_item_list); - rbml_w.wr_tagged_str(tag_meta_item_name, name); - for inner_item in items { - encode_meta_item(rbml_w, &**inner_item); - } - rbml_w.end_tag(); - } - } -} - -fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { - rbml_w.start_tag(tag_attributes); - for attr in attrs { - rbml_w.start_tag(tag_attribute); - rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8); - encode_meta_item(rbml_w, &*attr.node.value); - rbml_w.end_tag(); - } - rbml_w.end_tag(); -} - -fn encode_unsafety(rbml_w: &mut Encoder, unsafety: hir::Unsafety) { - let byte: u8 = match unsafety { - hir::Unsafety::Normal => 0, - hir::Unsafety::Unsafe => 1, - }; - rbml_w.wr_tagged_u8(tag_unsafety, byte); -} - -fn encode_paren_sugar(rbml_w: &mut Encoder, paren_sugar: bool) { - let byte: u8 = if paren_sugar {1} else {0}; - rbml_w.wr_tagged_u8(tag_paren_sugar, byte); -} - -fn encode_defaulted(rbml_w: &mut Encoder, is_defaulted: bool) { - let byte: u8 = if is_defaulted {1} else {0}; - rbml_w.wr_tagged_u8(tag_defaulted_trait, byte); -} - -fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[Name]) { - rbml_w.start_tag(tag_associated_type_names); - for &name in names { - rbml_w.wr_tagged_str(tag_associated_type_name, &name.as_str()); - } - rbml_w.end_tag(); -} - -fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) { - let byte: u8 = match polarity { - hir::ImplPolarity::Positive => 0, - hir::ImplPolarity::Negative => 1, - }; - rbml_w.wr_tagged_u8(tag_polarity, byte); -} - -fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { - fn get_ordered_deps(cstore: &cstore::CStore) - -> Vec<(CrateNum, Rc)> { - // Pull the cnums and name,vers,hash out of cstore - let mut deps = Vec::new(); - cstore.iter_crate_data(|cnum, val| { - deps.push((cnum, val.clone())); - }); - - // Sort by cnum - deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0)); - - // Sanity-check the crate numbers - let mut expected_cnum = 1; - for &(n, _) in &deps { - assert_eq!(n, expected_cnum); - expected_cnum += 1; - } - - deps - } - - // We're just going to write a list of crate 'name-hash-version's, with - // the assumption that they are numbered 1 to n. - // FIXME (#2166): This is not nearly enough to support correct versioning - // but is enough to get transitive crate dependencies working. - rbml_w.start_tag(tag_crate_deps); - for (_cnum, dep) in get_ordered_deps(cstore) { - encode_crate_dep(rbml_w, &dep); - } - rbml_w.end_tag(); -} - -fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_lang_items); - - for (i, &opt_def_id) in ecx.tcx.lang_items.items() { - if let Some(def_id) = opt_def_id { - if def_id.is_local() { - rbml_w.start_tag(tag_lang_items_item); - rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32); - rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32()); - rbml_w.end_tag(); - } - } - } - - for i in &ecx.tcx.lang_items.missing { - rbml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32); - } - - rbml_w.end_tag(); // tag_lang_items -} - -fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_native_libraries); - - for &(ref lib, kind) in ecx.tcx.sess.cstore.used_libraries().iter() { - match kind { - cstore::NativeStatic => {} // these libraries are not propagated - cstore::NativeFramework | cstore::NativeUnknown => { - rbml_w.start_tag(tag_native_libraries_lib); - rbml_w.wr_tagged_u32(tag_native_libraries_kind, kind as u32); - rbml_w.wr_tagged_str(tag_native_libraries_name, lib); - rbml_w.end_tag(); - } - } - } - - rbml_w.end_tag(); -} - -fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) { - match ecx.tcx.sess.plugin_registrar_fn.get() { - Some(id) => { - let def_id = ecx.tcx.map.local_def_id(id); - rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32()); - } - None => {} - } -} - -fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_codemap); - let codemap = ecx.tcx.sess.codemap(); - - for filemap in &codemap.files.borrow()[..] { - - if filemap.lines.borrow().is_empty() || filemap.is_imported() { - // No need to export empty filemaps, as they can't contain spans - // that need translation. - // Also no need to re-export imported filemaps, as any downstream - // crate will import them from their original source. - continue; - } - - rbml_w.start_tag(tag_codemap_filemap); - filemap.encode(rbml_w); - rbml_w.end_tag(); - } - - rbml_w.end_tag(); -} - -/// Serialize the text of the exported macros -fn encode_macro_defs(rbml_w: &mut Encoder, - krate: &hir::Crate) { - rbml_w.start_tag(tag_macro_defs); - for def in &krate.exported_macros { - rbml_w.start_tag(tag_macro_def); - - encode_name(rbml_w, def.name); - encode_attributes(rbml_w, &def.attrs); - - rbml_w.wr_tagged_str(tag_macro_def_body, - &::syntax::print::pprust::tts_to_string(&def.body)); - - rbml_w.end_tag(); - } - rbml_w.end_tag(); -} - -fn encode_struct_field_attrs(ecx: &EncodeContext, - rbml_w: &mut Encoder, - krate: &hir::Crate) { - struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> { - ecx: &'a EncodeContext<'b, 'tcx>, - rbml_w: &'a mut Encoder<'c>, - } - - impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> { - fn visit_struct_field(&mut self, field: &hir::StructField) { - self.rbml_w.start_tag(tag_struct_field); - let def_id = self.ecx.tcx.map.local_def_id(field.node.id); - encode_def_id(self.rbml_w, def_id); - encode_attributes(self.rbml_w, &field.node.attrs); - self.rbml_w.end_tag(); - } - } - - rbml_w.start_tag(tag_struct_fields); - krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w }); - rbml_w.end_tag(); -} - - - -struct ImplVisitor<'a, 'tcx:'a> { - tcx: &'a ty::ctxt<'tcx>, - impls: FnvHashMap> -} - -impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { - fn visit_item(&mut self, item: &hir::Item) { - if let hir::ItemImpl(..) = item.node { - let impl_id = self.tcx.map.local_def_id(item.id); - if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) { - self.impls.entry(trait_ref.def_id) - .or_insert(vec![]) - .push(impl_id); - } - } - } -} - -/// Encodes an index, mapping each trait to its (local) implementations. -fn encode_impls<'a>(ecx: &'a EncodeContext, - krate: &hir::Crate, - rbml_w: &'a mut Encoder) { - let mut visitor = ImplVisitor { - tcx: ecx.tcx, - impls: FnvHashMap() - }; - krate.visit_all_items(&mut visitor); - - rbml_w.start_tag(tag_impls); - for (trait_, trait_impls) in visitor.impls { - rbml_w.start_tag(tag_impls_trait); - encode_def_id(rbml_w, trait_); - for impl_ in trait_impls { - rbml_w.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_)); - } - rbml_w.end_tag(); - } - rbml_w.end_tag(); -} - -fn encode_misc_info(ecx: &EncodeContext, - krate: &hir::Crate, - rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_misc_info); - rbml_w.start_tag(tag_misc_info_crate_items); - for item_id in &krate.module.item_ids { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); - - let item = ecx.tcx.map.expect_item(item_id.id); - each_auxiliary_node_id(item, |auxiliary_node_id| { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); - true - }); - } - - // Encode reexports for the root module. - encode_reexports(ecx, rbml_w, 0); - - rbml_w.end_tag(); - rbml_w.end_tag(); -} - -// Encodes all reachable symbols in this crate into the metadata. -// -// This pass is seeded off the reachability list calculated in the -// middle::reachable module but filters out items that either don't have a -// symbol associated with them (they weren't translated) or if they're an FFI -// definition (as that's not defined in this crate). -fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_reachable_ids); - for &id in ecx.reachable { - let def_id = ecx.tcx.map.local_def_id(id); - rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32()); - } - rbml_w.end_tag(); -} - -fn encode_crate_dep(rbml_w: &mut Encoder, - dep: &cstore::crate_metadata) { - rbml_w.start_tag(tag_crate_dep); - rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); - let hash = decoder::get_crate_hash(dep.data()); - rbml_w.wr_tagged_str(tag_crate_dep_hash, hash.as_str()); - rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked, - dep.explicitly_linked.get() as u8); - rbml_w.end_tag(); -} - -fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) { - rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str()); -} - -fn encode_rustc_version(rbml_w: &mut Encoder) { - rbml_w.wr_tagged_str(tag_rustc_version, &rustc_version()); -} - -fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) { - rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name); -} - -fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) { - rbml_w.wr_tagged_str(tag_crate_triple, triple); -} - -fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) { - let tag = tag_dylib_dependency_formats; - match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { - Some(arr) => { - let s = arr.iter().enumerate().filter_map(|(i, slot)| { - let kind = match *slot { - Linkage::NotLinked | - Linkage::IncludedFromDylib => return None, - Linkage::Dynamic => "d", - Linkage::Static => "s", - }; - Some(format!("{}:{}", i + 1, kind)) - }).collect::>(); - rbml_w.wr_tagged_str(tag, &s.join(",")); - } - None => { - rbml_w.wr_tagged_str(tag, ""); - } - } -} - -// NB: Increment this as you change the metadata encoding version. -#[allow(non_upper_case_globals)] -pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ]; - -pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec { - let mut wr = Cursor::new(Vec::new()); - encode_metadata_inner(&mut wr, parms, krate); - - // RBML compacts the encoded bytes whenever appropriate, - // so there are some garbages left after the end of the data. - let metalen = wr.seek(SeekFrom::Current(0)).unwrap() as usize; - let mut v = wr.into_inner(); - v.truncate(metalen); - assert_eq!(v.len(), metalen); - - // And here we run into yet another obscure archive bug: in which metadata - // loaded from archives may have trailing garbage bytes. Awhile back one of - // our tests was failing sporadically on the OSX 64-bit builders (both nopt - // and opt) by having rbml generate an out-of-bounds panic when looking at - // metadata. - // - // Upon investigation it turned out that the metadata file inside of an rlib - // (and ar archive) was being corrupted. Some compilations would generate a - // metadata file which would end in a few extra bytes, while other - // compilations would not have these extra bytes appended to the end. These - // extra bytes were interpreted by rbml as an extra tag, so they ended up - // being interpreted causing the out-of-bounds. - // - // The root cause of why these extra bytes were appearing was never - // discovered, and in the meantime the solution we're employing is to insert - // the length of the metadata to the start of the metadata. Later on this - // will allow us to slice the metadata to the precise length that we just - // generated regardless of trailing bytes that end up in it. - let len = v.len() as u32; - v.insert(0, (len >> 0) as u8); - v.insert(0, (len >> 8) as u8); - v.insert(0, (len >> 16) as u8); - v.insert(0, (len >> 24) as u8); - return v; -} - -fn encode_metadata_inner(wr: &mut Cursor>, - parms: EncodeParams, - krate: &hir::Crate) { - struct Stats { - attr_bytes: u64, - dep_bytes: u64, - lang_item_bytes: u64, - native_lib_bytes: u64, - plugin_registrar_fn_bytes: u64, - codemap_bytes: u64, - macro_defs_bytes: u64, - impl_bytes: u64, - misc_bytes: u64, - item_bytes: u64, - index_bytes: u64, - xref_bytes: u64, - zero_bytes: u64, - total_bytes: u64, - } - let mut stats = Stats { - attr_bytes: 0, - dep_bytes: 0, - lang_item_bytes: 0, - native_lib_bytes: 0, - plugin_registrar_fn_bytes: 0, - codemap_bytes: 0, - macro_defs_bytes: 0, - impl_bytes: 0, - misc_bytes: 0, - item_bytes: 0, - index_bytes: 0, - xref_bytes: 0, - zero_bytes: 0, - total_bytes: 0, - }; - let EncodeParams { - item_symbols, - diag, - tcx, - reexports, - cstore, - encode_inlined_item, - link_meta, - reachable, - .. - } = parms; - let ecx = EncodeContext { - diag: diag, - tcx: tcx, - reexports: reexports, - item_symbols: item_symbols, - link_meta: link_meta, - cstore: cstore, - encode_inlined_item: RefCell::new(encode_inlined_item), - type_abbrevs: RefCell::new(FnvHashMap()), - reachable: reachable, - }; - - let mut rbml_w = Encoder::new(wr); - - encode_rustc_version(&mut rbml_w); - encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name); - encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple); - encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash); - encode_dylib_dependency_formats(&mut rbml_w, &ecx); - - let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_attributes(&mut rbml_w, &krate.attrs); - stats.attr_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_crate_deps(&mut rbml_w, ecx.cstore); - stats.dep_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - // Encode the language items. - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_lang_items(&ecx, &mut rbml_w); - stats.lang_item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - // Encode the native libraries used - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_native_libraries(&ecx, &mut rbml_w); - stats.native_lib_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - // Encode the plugin registrar function - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_plugin_registrar_fn(&ecx, &mut rbml_w); - stats.plugin_registrar_fn_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - // Encode codemap - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_codemap(&ecx, &mut rbml_w); - stats.codemap_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - // Encode macro definitions - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_macro_defs(&mut rbml_w, krate); - stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - // Encode the def IDs of impls, for coherence checking. - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_impls(&ecx, krate, &mut rbml_w); - stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - // Encode miscellaneous info. - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_misc_info(&ecx, krate, &mut rbml_w); - encode_reachable(&ecx, &mut rbml_w); - stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - // Encode and index the items. - rbml_w.start_tag(tag_items); - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - let index = encode_info_for_items(&ecx, &mut rbml_w); - stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - rbml_w.end_tag(); - - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_item_index(&mut rbml_w, index.items); - stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_xrefs(&ecx, &mut rbml_w, index.xrefs); - stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - - encode_struct_field_attrs(&ecx, &mut rbml_w, krate); - - stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - - if tcx.sess.meta_stats() { - for e in rbml_w.writer.get_ref() { - if *e == 0 { - stats.zero_bytes += 1; - } - } - - println!("metadata stats:"); - println!(" attribute bytes: {}", stats.attr_bytes); - println!(" dep bytes: {}", stats.dep_bytes); - println!(" lang item bytes: {}", stats.lang_item_bytes); - println!(" native bytes: {}", stats.native_lib_bytes); - println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes); - println!(" codemap bytes: {}", stats.codemap_bytes); - println!(" macro def bytes: {}", stats.macro_defs_bytes); - println!(" impl bytes: {}", stats.impl_bytes); - println!(" misc bytes: {}", stats.misc_bytes); - println!(" item bytes: {}", stats.item_bytes); - println!(" index bytes: {}", stats.index_bytes); - println!(" xref bytes: {}", stats.xref_bytes); - println!(" zero bytes: {}", stats.zero_bytes); - println!(" total bytes: {}", stats.total_bytes); - } -} - -// Get the encoded string for a type -pub fn encoded_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> Vec { - let mut wr = Cursor::new(Vec::new()); - tyencode::enc_ty(&mut Encoder::new(&mut wr), &tyencode::ctxt { - diag: tcx.sess.diagnostic(), - ds: def_to_string, - tcx: tcx, - abbrevs: &RefCell::new(FnvHashMap()) - }, t); - wr.into_inner() -} diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs deleted file mode 100644 index 09c6b54d99c..00000000000 --- a/src/librustc/metadata/filesearch.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types)] - -pub use self::FileMatch::*; - -use std::collections::HashSet; -use std::env; -use std::fs; -use std::io::prelude::*; -use std::path::{Path, PathBuf}; - -use session::search_paths::{SearchPaths, PathKind}; -use util::fs as rustcfs; - -#[derive(Copy, Clone)] -pub enum FileMatch { - FileMatches, - FileDoesntMatch, -} - -// A module for searching for libraries -// FIXME (#2658): I'm not happy how this module turned out. Should -// probably just be folded into cstore. - -pub struct FileSearch<'a> { - pub sysroot: &'a Path, - pub search_paths: &'a SearchPaths, - pub triple: &'a str, - pub kind: PathKind, -} - -impl<'a> FileSearch<'a> { - pub fn for_each_lib_search_path(&self, mut f: F) where - F: FnMut(&Path, PathKind) - { - let mut visited_dirs = HashSet::new(); - - for (path, kind) in self.search_paths.iter(self.kind) { - f(path, kind); - visited_dirs.insert(path.to_path_buf()); - } - - debug!("filesearch: searching lib path"); - let tlib_path = make_target_lib_path(self.sysroot, - self.triple); - if !visited_dirs.contains(&tlib_path) { - f(&tlib_path, PathKind::All); - } - - visited_dirs.insert(tlib_path); - } - - pub fn get_lib_path(&self) -> PathBuf { - make_target_lib_path(self.sysroot, self.triple) - } - - pub fn search(&self, mut pick: F) - where F: FnMut(&Path, PathKind) -> FileMatch - { - self.for_each_lib_search_path(|lib_search_path, kind| { - debug!("searching {}", lib_search_path.display()); - match fs::read_dir(lib_search_path) { - Ok(files) => { - let files = files.filter_map(|p| p.ok().map(|s| s.path())) - .collect::>(); - fn is_rlib(p: &Path) -> bool { - p.extension().and_then(|s| s.to_str()) == Some("rlib") - } - // Reading metadata out of rlibs is faster, and if we find both - // an rlib and a dylib we only read one of the files of - // metadata, so in the name of speed, bring all rlib files to - // the front of the search list. - let files1 = files.iter().filter(|p| is_rlib(p)); - let files2 = files.iter().filter(|p| !is_rlib(p)); - for path in files1.chain(files2) { - debug!("testing {}", path.display()); - let maybe_picked = pick(path, kind); - match maybe_picked { - FileMatches => { - debug!("picked {}", path.display()); - } - FileDoesntMatch => { - debug!("rejected {}", path.display()); - } - } - } - } - Err(..) => (), - } - }); - } - - pub fn new(sysroot: &'a Path, - triple: &'a str, - search_paths: &'a SearchPaths, - kind: PathKind) -> FileSearch<'a> { - debug!("using sysroot = {}, triple = {}", sysroot.display(), triple); - FileSearch { - sysroot: sysroot, - search_paths: search_paths, - triple: triple, - kind: kind, - } - } - - // Returns a list of directories where target-specific dylibs might be located. - pub fn get_dylib_search_paths(&self) -> Vec { - let mut paths = Vec::new(); - self.for_each_lib_search_path(|lib_search_path, _| { - paths.push(lib_search_path.to_path_buf()); - }); - paths - } - - // Returns a list of directories where target-specific tool binaries are located. - pub fn get_tools_search_paths(&self) -> Vec { - let mut p = PathBuf::from(self.sysroot); - p.push(&find_libdir(self.sysroot)); - p.push(&rustlibdir()); - p.push(&self.triple); - p.push("bin"); - vec![p] - } -} - -pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let mut p = PathBuf::from(&find_libdir(sysroot)); - assert!(p.is_relative()); - p.push(&rustlibdir()); - p.push(target_triple); - p.push("lib"); - p -} - -fn make_target_lib_path(sysroot: &Path, - target_triple: &str) -> PathBuf { - sysroot.join(&relative_target_lib_path(sysroot, target_triple)) -} - -pub fn get_or_default_sysroot() -> PathBuf { - // Follow symlinks. If the resolved path is relative, make it absolute. - fn canonicalize(path: Option) -> Option { - path.and_then(|path| { - match fs::canonicalize(&path) { - // See comments on this target function, but the gist is that - // gcc chokes on verbatim paths which fs::canonicalize generates - // so we try to avoid those kinds of paths. - Ok(canon) => Some(rustcfs::fix_windows_verbatim_for_gcc(&canon)), - Err(e) => panic!("failed to get realpath: {}", e), - } - }) - } - - match canonicalize(env::current_exe().ok()) { - Some(mut p) => { p.pop(); p.pop(); p } - None => panic!("can't determine value for sysroot") - } -} - -// The name of the directory rustc expects libraries to be located. -fn find_libdir(sysroot: &Path) -> String { - // FIXME: This is a quick hack to make the rustc binary able to locate - // Rust libraries in Linux environments where libraries might be installed - // to lib64/lib32. This would be more foolproof by basing the sysroot off - // of the directory where librustc is located, rather than where the rustc - // binary is. - //If --libdir is set during configuration to the value other than - // "lib" (i.e. non-default), this value is used (see issue #16552). - - match option_env!("CFG_LIBDIR_RELATIVE") { - Some(libdir) if libdir != "lib" => return libdir.to_string(), - _ => if sysroot.join(&primary_libdir_name()).join(&rustlibdir()).exists() { - return primary_libdir_name(); - } else { - return secondary_libdir_name(); - } - } - - #[cfg(target_pointer_width = "64")] - fn primary_libdir_name() -> String { - "lib64".to_string() - } - - #[cfg(target_pointer_width = "32")] - fn primary_libdir_name() -> String { - "lib32".to_string() - } - - fn secondary_libdir_name() -> String { - "lib".to_string() - } -} - -// The name of rustc's own place to organize libraries. -// Used to be "rustc", now the default is "rustlib" -pub fn rustlibdir() -> String { - "rustlib".to_string() -} diff --git a/src/librustc/metadata/index.rs b/src/librustc/metadata/index.rs deleted file mode 100644 index 60bbdaddd75..00000000000 --- a/src/librustc/metadata/index.rs +++ /dev/null @@ -1,145 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::def_id::{DefId, DefIndex}; -use rbml; -use std::io::{Cursor, Write}; -use std::slice; -use std::u32; - -/// As part of the metadata, we generate an index that stores, for -/// each DefIndex, the position of the corresponding RBML document (if -/// any). This is just a big `[u32]` slice, where an entry of -/// `u32::MAX` indicates that there is no RBML document. This little -/// struct just stores the offsets within the metadata of the start -/// and end of this slice. These are actually part of an RBML -/// document, but for looking things up in the metadata, we just -/// discard the RBML positioning and jump directly to the data. -pub struct Index { - data_start: usize, - data_end: usize, -} - -impl Index { - /// Given the RBML doc representing the index, save the offests - /// for later. - pub fn from_rbml(index: rbml::Doc) -> Index { - Index { data_start: index.start, data_end: index.end } - } - - /// Given the metadata, extract out the offset of a particular - /// DefIndex (if any). - #[inline(never)] - pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option { - let words = bytes_to_words(&bytes[self.data_start..self.data_end]); - let index = def_index.as_usize(); - - debug!("lookup_item: index={:?} words.len={:?}", - index, words.len()); - - let position = u32::from_be(words[index]); - if position == u32::MAX { - debug!("lookup_item: position=u32::MAX"); - None - } else { - debug!("lookup_item: position={:?}", position); - Some(position) - } - } -} - -/// While we are generating the metadata, we also track the position -/// of each DefIndex. It is not required that all definitions appear -/// in the metadata, nor that they are serialized in order, and -/// therefore we first allocate the vector here and fill it with -/// `u32::MAX`. Whenever an index is visited, we fill in the -/// appropriate spot by calling `record_position`. We should never -/// visit the same index twice. -pub struct IndexData { - positions: Vec, -} - -impl IndexData { - pub fn new(max_index: usize) -> IndexData { - IndexData { - positions: vec![u32::MAX; max_index] - } - } - - pub fn record(&mut self, def_id: DefId, position: u64) { - assert!(def_id.is_local()); - self.record_index(def_id.index, position) - } - - pub fn record_index(&mut self, item: DefIndex, position: u64) { - let item = item.as_usize(); - - assert!(position < (u32::MAX as u64)); - let position = position as u32; - - assert!(self.positions[item] == u32::MAX, - "recorded position for item {:?} twice, first at {:?} and now at {:?}", - item, self.positions[item], position); - - self.positions[item] = position; - } - - pub fn write_index(&self, buf: &mut Cursor>) { - for &position in &self.positions { - write_be_u32(buf, position); - } - } -} - -/// A dense index with integer keys. Different API from IndexData (should -/// these be merged?) -pub struct DenseIndex { - start: usize, - end: usize -} - -impl DenseIndex { - pub fn lookup(&self, buf: &[u8], ix: u32) -> Option { - let data = bytes_to_words(&buf[self.start..self.end]); - data.get(ix as usize).map(|d| u32::from_be(*d)) - } - pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self { - assert!((end-start)%4 == 0 && start <= end && end <= buf.len()); - DenseIndex { - start: start, - end: end - } - } -} - -pub fn write_dense_index(entries: Vec, buf: &mut Cursor>) { - let elen = entries.len(); - assert!(elen < u32::MAX as usize); - - for entry in entries { - write_be_u32(buf, entry); - } - - info!("write_dense_index: {} entries", elen); -} - -fn write_be_u32(w: &mut W, u: u32) { - let _ = w.write_all(&[ - (u >> 24) as u8, - (u >> 16) as u8, - (u >> 8) as u8, - (u >> 0) as u8, - ]); -} - -fn bytes_to_words(b: &[u8]) -> &[u32] { - assert!(b.len() % 4 == 0); - unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) } -} diff --git a/src/librustc/metadata/inline.rs b/src/librustc/metadata/inline.rs deleted file mode 100644 index e621a4166d7..00000000000 --- a/src/librustc/metadata/inline.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::def_id::DefId; -use rustc_front::hir; -use rustc_front::util::IdVisitor; -use syntax::ast_util::{IdRange, IdRangeComputingVisitor, IdVisitingOperation}; -use syntax::ptr::P; -use rustc_front::intravisit::Visitor; -use self::InlinedItem::*; - -/// The data we save and restore about an inlined item or method. This is not -/// part of the AST that we parse from a file, but it becomes part of the tree -/// that we trans. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum InlinedItem { - Item(P), - TraitItem(DefId /* impl id */, P), - ImplItem(DefId /* impl id */, P), - Foreign(P), -} - -/// A borrowed version of `hir::InlinedItem`. -pub enum InlinedItemRef<'a> { - Item(&'a hir::Item), - TraitItem(DefId, &'a hir::TraitItem), - ImplItem(DefId, &'a hir::ImplItem), - Foreign(&'a hir::ForeignItem) -} - -impl InlinedItem { - pub fn visit<'ast,V>(&'ast self, visitor: &mut V) - where V: Visitor<'ast> - { - match *self { - Item(ref i) => visitor.visit_item(&**i), - Foreign(ref i) => visitor.visit_foreign_item(&**i), - TraitItem(_, ref ti) => visitor.visit_trait_item(ti), - ImplItem(_, ref ii) => visitor.visit_impl_item(ii), - } - } - - pub fn visit_ids(&self, operation: &mut O) { - let mut id_visitor = IdVisitor::new(operation); - self.visit(&mut id_visitor); - } - - pub fn compute_id_range(&self) -> IdRange { - let mut visitor = IdRangeComputingVisitor::new(); - self.visit_ids(&mut visitor); - visitor.result() - } -} diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs deleted file mode 100644 index ca1562683ef..00000000000 --- a/src/librustc/metadata/loader.rs +++ /dev/null @@ -1,852 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Finds crate binaries and loads their metadata -//! -//! Might I be the first to welcome you to a world of platform differences, -//! version requirements, dependency graphs, conflicting desires, and fun! This -//! is the major guts (along with metadata::creader) of the compiler for loading -//! crates and resolving dependencies. Let's take a tour! -//! -//! # The problem -//! -//! Each invocation of the compiler is immediately concerned with one primary -//! problem, to connect a set of crates to resolved crates on the filesystem. -//! Concretely speaking, the compiler follows roughly these steps to get here: -//! -//! 1. Discover a set of `extern crate` statements. -//! 2. Transform these directives into crate names. If the directive does not -//! have an explicit name, then the identifier is the name. -//! 3. For each of these crate names, find a corresponding crate on the -//! filesystem. -//! -//! Sounds easy, right? Let's walk into some of the nuances. -//! -//! ## Transitive Dependencies -//! -//! Let's say we've got three crates: A, B, and C. A depends on B, and B depends -//! on C. When we're compiling A, we primarily need to find and locate B, but we -//! also end up needing to find and locate C as well. -//! -//! The reason for this is that any of B's types could be composed of C's types, -//! any function in B could return a type from C, etc. To be able to guarantee -//! that we can always typecheck/translate any function, we have to have -//! complete knowledge of the whole ecosystem, not just our immediate -//! dependencies. -//! -//! So now as part of the "find a corresponding crate on the filesystem" step -//! above, this involves also finding all crates for *all upstream -//! dependencies*. This includes all dependencies transitively. -//! -//! ## Rlibs and Dylibs -//! -//! The compiler has two forms of intermediate dependencies. These are dubbed -//! rlibs and dylibs for the static and dynamic variants, respectively. An rlib -//! is a rustc-defined file format (currently just an ar archive) while a dylib -//! is a platform-defined dynamic library. Each library has a metadata somewhere -//! inside of it. -//! -//! When translating a crate name to a crate on the filesystem, we all of a -//! sudden need to take into account both rlibs and dylibs! Linkage later on may -//! use either one of these files, as each has their pros/cons. The job of crate -//! loading is to discover what's possible by finding all candidates. -//! -//! Most parts of this loading systems keep the dylib/rlib as just separate -//! variables. -//! -//! ## Where to look? -//! -//! We can't exactly scan your whole hard drive when looking for dependencies, -//! so we need to places to look. Currently the compiler will implicitly add the -//! target lib search path ($prefix/lib/rustlib/$target/lib) to any compilation, -//! and otherwise all -L flags are added to the search paths. -//! -//! ## What criterion to select on? -//! -//! This a pretty tricky area of loading crates. Given a file, how do we know -//! whether it's the right crate? Currently, the rules look along these lines: -//! -//! 1. Does the filename match an rlib/dylib pattern? That is to say, does the -//! filename have the right prefix/suffix? -//! 2. Does the filename have the right prefix for the crate name being queried? -//! This is filtering for files like `libfoo*.rlib` and such. -//! 3. Is the file an actual rust library? This is done by loading the metadata -//! from the library and making sure it's actually there. -//! 4. Does the name in the metadata agree with the name of the library? -//! 5. Does the target in the metadata agree with the current target? -//! 6. Does the SVH match? (more on this later) -//! -//! If the file answers `yes` to all these questions, then the file is -//! considered as being *candidate* for being accepted. It is illegal to have -//! more than two candidates as the compiler has no method by which to resolve -//! this conflict. Additionally, rlib/dylib candidates are considered -//! separately. -//! -//! After all this has happened, we have 1 or two files as candidates. These -//! represent the rlib/dylib file found for a library, and they're returned as -//! being found. -//! -//! ### What about versions? -//! -//! A lot of effort has been put forth to remove versioning from the compiler. -//! There have been forays in the past to have versioning baked in, but it was -//! largely always deemed insufficient to the point that it was recognized that -//! it's probably something the compiler shouldn't do anyway due to its -//! complicated nature and the state of the half-baked solutions. -//! -//! With a departure from versioning, the primary criterion for loading crates -//! is just the name of a crate. If we stopped here, it would imply that you -//! could never link two crates of the same name from different sources -//! together, which is clearly a bad state to be in. -//! -//! To resolve this problem, we come to the next section! -//! -//! # Expert Mode -//! -//! A number of flags have been added to the compiler to solve the "version -//! problem" in the previous section, as well as generally enabling more -//! powerful usage of the crate loading system of the compiler. The goal of -//! these flags and options are to enable third-party tools to drive the -//! compiler with prior knowledge about how the world should look. -//! -//! ## The `--extern` flag -//! -//! The compiler accepts a flag of this form a number of times: -//! -//! ```text -//! --extern crate-name=path/to/the/crate.rlib -//! ``` -//! -//! This flag is basically the following letter to the compiler: -//! -//! > Dear rustc, -//! > -//! > When you are attempting to load the immediate dependency `crate-name`, I -//! > would like you to assume that the library is located at -//! > `path/to/the/crate.rlib`, and look nowhere else. Also, please do not -//! > assume that the path I specified has the name `crate-name`. -//! -//! This flag basically overrides most matching logic except for validating that -//! the file is indeed a rust library. The same `crate-name` can be specified -//! twice to specify the rlib/dylib pair. -//! -//! ## Enabling "multiple versions" -//! -//! This basically boils down to the ability to specify arbitrary packages to -//! the compiler. For example, if crate A wanted to use Bv1 and Bv2, then it -//! would look something like: -//! -//! ```ignore -//! extern crate b1; -//! extern crate b2; -//! -//! fn main() {} -//! ``` -//! -//! and the compiler would be invoked as: -//! -//! ```text -//! rustc a.rs --extern b1=path/to/libb1.rlib --extern b2=path/to/libb2.rlib -//! ``` -//! -//! In this scenario there are two crates named `b` and the compiler must be -//! manually driven to be informed where each crate is. -//! -//! ## Frobbing symbols -//! -//! One of the immediate problems with linking the same library together twice -//! in the same problem is dealing with duplicate symbols. The primary way to -//! deal with this in rustc is to add hashes to the end of each symbol. -//! -//! In order to force hashes to change between versions of a library, if -//! desired, the compiler exposes an option `-C metadata=foo`, which is used to -//! initially seed each symbol hash. The string `foo` is prepended to each -//! string-to-hash to ensure that symbols change over time. -//! -//! ## Loading transitive dependencies -//! -//! Dealing with same-named-but-distinct crates is not just a local problem, but -//! one that also needs to be dealt with for transitive dependencies. Note that -//! in the letter above `--extern` flags only apply to the *local* set of -//! dependencies, not the upstream transitive dependencies. Consider this -//! dependency graph: -//! -//! ```text -//! A.1 A.2 -//! | | -//! | | -//! B C -//! \ / -//! \ / -//! D -//! ``` -//! -//! In this scenario, when we compile `D`, we need to be able to distinctly -//! resolve `A.1` and `A.2`, but an `--extern` flag cannot apply to these -//! transitive dependencies. -//! -//! Note that the key idea here is that `B` and `C` are both *already compiled*. -//! That is, they have already resolved their dependencies. Due to unrelated -//! technical reasons, when a library is compiled, it is only compatible with -//! the *exact same* version of the upstream libraries it was compiled against. -//! We use the "Strict Version Hash" to identify the exact copy of an upstream -//! library. -//! -//! With this knowledge, we know that `B` and `C` will depend on `A` with -//! different SVH values, so we crawl the normal `-L` paths looking for -//! `liba*.rlib` and filter based on the contained SVH. -//! -//! In the end, this ends up not needing `--extern` to specify upstream -//! transitive dependencies. -//! -//! # Wrapping up -//! -//! That's the general overview of loading crates in the compiler, but it's by -//! no means all of the necessary details. Take a look at the rest of -//! metadata::loader or metadata::creader for all the juicy details! - -use back::svh::Svh; -use session::Session; -use session::search_paths::PathKind; -use llvm; -use llvm::{False, ObjectFile, mk_section_iter}; -use llvm::archive_ro::ArchiveRO; -use metadata::cstore::{MetadataBlob, MetadataVec, MetadataArchive}; -use metadata::decoder; -use metadata::encoder; -use metadata::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; -use syntax::codemap::Span; -use syntax::diagnostic::SpanHandler; -use util::common; -use rustc_back::target::Target; - -use std::cmp; -use std::collections::HashMap; -use std::fs; -use std::io::prelude::*; -use std::io; -use std::path::{Path, PathBuf}; -use std::ptr; -use std::slice; -use std::time::Duration; - -use flate; - -pub struct CrateMismatch { - path: PathBuf, - got: String, -} - -pub struct Context<'a> { - pub sess: &'a Session, - pub span: Span, - pub ident: &'a str, - pub crate_name: &'a str, - pub hash: Option<&'a Svh>, - // points to either self.sess.target.target or self.sess.host, must match triple - pub target: &'a Target, - pub triple: &'a str, - pub filesearch: FileSearch<'a>, - pub root: &'a Option, - pub rejected_via_hash: Vec, - pub rejected_via_triple: Vec, - pub rejected_via_kind: Vec, - pub should_match_name: bool, -} - -pub struct Library { - pub dylib: Option<(PathBuf, PathKind)>, - pub rlib: Option<(PathBuf, PathKind)>, - pub metadata: MetadataBlob, -} - -pub struct ArchiveMetadata { - _archive: ArchiveRO, - // points into self._archive - data: *const [u8], -} - -pub struct CratePaths { - pub ident: String, - pub dylib: Option, - pub rlib: Option -} - -pub const METADATA_FILENAME: &'static str = "rust.metadata.bin"; - -impl CratePaths { - fn paths(&self) -> Vec { - match (&self.dylib, &self.rlib) { - (&None, &None) => vec!(), - (&Some(ref p), &None) | - (&None, &Some(ref p)) => vec!(p.clone()), - (&Some(ref p1), &Some(ref p2)) => vec!(p1.clone(), p2.clone()), - } - } -} - -impl<'a> Context<'a> { - pub fn maybe_load_library_crate(&mut self) -> Option { - self.find_library_crate() - } - - pub fn load_library_crate(&mut self) -> Library { - match self.find_library_crate() { - Some(t) => t, - None => { - self.report_load_errs(); - unreachable!() - } - } - } - - pub fn report_load_errs(&mut self) { - let add = match self.root { - &None => String::new(), - &Some(ref r) => format!(" which `{}` depends on", - r.ident) - }; - if !self.rejected_via_hash.is_empty() { - span_err!(self.sess, self.span, E0460, - "found possibly newer version of crate `{}`{}", - self.ident, add); - } else if !self.rejected_via_triple.is_empty() { - span_err!(self.sess, self.span, E0461, - "couldn't find crate `{}` with expected target triple {}{}", - self.ident, self.triple, add); - } else if !self.rejected_via_kind.is_empty() { - span_err!(self.sess, self.span, E0462, - "found staticlib `{}` instead of rlib or dylib{}", - self.ident, add); - } else { - span_err!(self.sess, self.span, E0463, - "can't find crate for `{}`{}", - self.ident, add); - } - - if !self.rejected_via_triple.is_empty() { - let mismatches = self.rejected_via_triple.iter(); - for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() { - self.sess.fileline_note(self.span, - &format!("crate `{}`, path #{}, triple {}: {}", - self.ident, i+1, got, path.display())); - } - } - if !self.rejected_via_hash.is_empty() { - self.sess.span_note(self.span, "perhaps this crate needs \ - to be recompiled?"); - let mismatches = self.rejected_via_hash.iter(); - for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() { - self.sess.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); - } - match self.root { - &None => {} - &Some(ref r) => { - for (i, path) in r.paths().iter().enumerate() { - self.sess.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - r.ident, i+1, path.display())); - } - } - } - } - if !self.rejected_via_kind.is_empty() { - self.sess.fileline_help(self.span, "please recompile this crate using \ - --crate-type lib"); - let mismatches = self.rejected_via_kind.iter(); - for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { - self.sess.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); - } - } - self.sess.abort_if_errors(); - } - - fn find_library_crate(&mut self) -> Option { - // If an SVH is specified, then this is a transitive dependency that - // must be loaded via -L plus some filtering. - if self.hash.is_none() { - self.should_match_name = false; - if let Some(s) = self.sess.opts.externs.get(self.crate_name) { - return self.find_commandline_library(s); - } - self.should_match_name = true; - } - - let dypair = self.dylibname(); - - // want: crate_name.dir_part() + prefix + crate_name.file_part + "-" - let dylib_prefix = format!("{}{}", dypair.0, self.crate_name); - let rlib_prefix = format!("lib{}", self.crate_name); - let staticlib_prefix = format!("lib{}", self.crate_name); - - let mut candidates = HashMap::new(); - let mut staticlibs = vec!(); - - // First, find all possible candidate rlibs and dylibs purely based on - // the name of the files themselves. We're trying to match against an - // exact crate name and a possibly an exact hash. - // - // During this step, we can filter all found libraries based on the - // name and id found in the crate id (we ignore the path portion for - // filename matching), as well as the exact hash (if specified). If we - // end up having many candidates, we must look at the metadata to - // perform exact matches against hashes/crate ids. Note that opening up - // the metadata is where we do an exact match against the full contents - // of the crate id (path/name/id). - // - // The goal of this step is to look at as little metadata as possible. - self.filesearch.search(|path, kind| { - let file = match path.file_name().and_then(|s| s.to_str()) { - None => return FileDoesntMatch, - Some(file) => file, - }; - let (hash, rlib) = if file.starts_with(&rlib_prefix[..]) && - file.ends_with(".rlib") { - (&file[(rlib_prefix.len()) .. (file.len() - ".rlib".len())], - true) - } else if file.starts_with(&dylib_prefix) && - file.ends_with(&dypair.1) { - (&file[(dylib_prefix.len()) .. (file.len() - dypair.1.len())], - false) - } else { - if file.starts_with(&staticlib_prefix[..]) && - file.ends_with(".a") { - staticlibs.push(CrateMismatch { - path: path.to_path_buf(), - got: "static".to_string() - }); - } - return FileDoesntMatch - }; - info!("lib candidate: {}", path.display()); - - let hash_str = hash.to_string(); - let slot = candidates.entry(hash_str) - .or_insert_with(|| (HashMap::new(), HashMap::new())); - let (ref mut rlibs, ref mut dylibs) = *slot; - fs::canonicalize(path).map(|p| { - if rlib { - rlibs.insert(p, kind); - } else { - dylibs.insert(p, kind); - } - FileMatches - }).unwrap_or(FileDoesntMatch) - }); - self.rejected_via_kind.extend(staticlibs); - - // We have now collected all known libraries into a set of candidates - // keyed of the filename hash listed. For each filename, we also have a - // list of rlibs/dylibs that apply. Here, we map each of these lists - // (per hash), to a Library candidate for returning. - // - // A Library candidate is created if the metadata for the set of - // libraries corresponds to the crate id and hash criteria that this - // search is being performed for. - let mut libraries = Vec::new(); - for (_hash, (rlibs, dylibs)) in candidates { - let mut metadata = None; - let rlib = self.extract_one(rlibs, "rlib", &mut metadata); - let dylib = self.extract_one(dylibs, "dylib", &mut metadata); - match metadata { - Some(metadata) => { - libraries.push(Library { - dylib: dylib, - rlib: rlib, - metadata: metadata, - }) - } - None => {} - } - } - - // Having now translated all relevant found hashes into libraries, see - // what we've got and figure out if we found multiple candidates for - // libraries or not. - match libraries.len() { - 0 => None, - 1 => Some(libraries.into_iter().next().unwrap()), - _ => { - span_err!(self.sess, self.span, E0464, - "multiple matching crates for `{}`", - self.crate_name); - self.sess.note("candidates:"); - for lib in &libraries { - match lib.dylib { - Some((ref p, _)) => { - self.sess.note(&format!("path: {}", - p.display())); - } - None => {} - } - match lib.rlib { - Some((ref p, _)) => { - self.sess.note(&format!("path: {}", - p.display())); - } - None => {} - } - let data = lib.metadata.as_slice(); - let name = decoder::get_crate_name(data); - note_crate_name(self.sess.diagnostic(), &name); - } - None - } - } - } - - // Attempts to extract *one* library from the set `m`. If the set has no - // elements, `None` is returned. If the set has more than one element, then - // the errors and notes are emitted about the set of libraries. - // - // With only one library in the set, this function will extract it, and then - // read the metadata from it if `*slot` is `None`. If the metadata couldn't - // be read, it is assumed that the file isn't a valid rust library (no - // errors are emitted). - fn extract_one(&mut self, m: HashMap, flavor: &str, - slot: &mut Option) -> Option<(PathBuf, PathKind)> { - let mut ret = None::<(PathBuf, PathKind)>; - let mut error = 0; - - if slot.is_some() { - // FIXME(#10786): for an optimization, we only read one of the - // library's metadata sections. In theory we should - // read both, but reading dylib metadata is quite - // slow. - if m.is_empty() { - return None - } else if m.len() == 1 { - return Some(m.into_iter().next().unwrap()) - } - } - - for (lib, kind) in m { - info!("{} reading metadata from: {}", flavor, lib.display()); - let metadata = match get_metadata_section(self.target, &lib) { - Ok(blob) => { - if self.crate_matches(blob.as_slice(), &lib) { - blob - } else { - info!("metadata mismatch"); - continue - } - } - Err(err) => { - info!("no metadata found: {}", err); - continue - } - }; - // If we've already found a candidate and we're not matching hashes, - // emit an error about duplicate candidates found. If we're matching - // based on a hash, however, then if we've gotten this far both - // candidates have the same hash, so they're not actually - // duplicates that we should warn about. - if ret.is_some() && self.hash.is_none() { - span_err!(self.sess, self.span, E0465, - "multiple {} candidates for `{}` found", - flavor, self.crate_name); - self.sess.span_note(self.span, - &format!(r"candidate #1: {}", - ret.as_ref().unwrap().0 - .display())); - error = 1; - ret = None; - } - if error > 0 { - error += 1; - self.sess.span_note(self.span, - &format!(r"candidate #{}: {}", error, - lib.display())); - continue - } - *slot = Some(metadata); - ret = Some((lib, kind)); - } - return if error > 0 {None} else {ret} - } - - fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool { - if self.should_match_name { - match decoder::maybe_get_crate_name(crate_data) { - Some(ref name) if self.crate_name == *name => {} - _ => { info!("Rejecting via crate name"); return false } - } - } - let hash = match decoder::maybe_get_crate_hash(crate_data) { - Some(hash) => hash, None => { - info!("Rejecting via lack of crate hash"); - return false; - } - }; - - let triple = match decoder::get_crate_triple(crate_data) { - None => { debug!("triple not present"); return false } - Some(t) => t, - }; - if triple != self.triple { - info!("Rejecting via crate triple: expected {} got {}", self.triple, triple); - self.rejected_via_triple.push(CrateMismatch { - path: libpath.to_path_buf(), - got: triple.to_string() - }); - return false; - } - - match self.hash { - None => true, - Some(myhash) => { - if *myhash != hash { - info!("Rejecting via hash: expected {} got {}", *myhash, hash); - self.rejected_via_hash.push(CrateMismatch { - path: libpath.to_path_buf(), - got: myhash.as_str().to_string() - }); - false - } else { - true - } - } - } - } - - - // Returns the corresponding (prefix, suffix) that files need to have for - // dynamic libraries - fn dylibname(&self) -> (String, String) { - let t = &self.target; - (t.options.dll_prefix.clone(), t.options.dll_suffix.clone()) - } - - fn find_commandline_library(&mut self, locs: &[String]) -> Option { - // First, filter out all libraries that look suspicious. We only accept - // files which actually exist that have the correct naming scheme for - // rlibs/dylibs. - let sess = self.sess; - let dylibname = self.dylibname(); - let mut rlibs = HashMap::new(); - let mut dylibs = HashMap::new(); - { - let locs = locs.iter().map(|l| PathBuf::from(l)).filter(|loc| { - if !loc.exists() { - sess.err(&format!("extern location for {} does not exist: {}", - self.crate_name, loc.display())); - return false; - } - let file = match loc.file_name().and_then(|s| s.to_str()) { - Some(file) => file, - None => { - sess.err(&format!("extern location for {} is not a file: {}", - self.crate_name, loc.display())); - return false; - } - }; - if file.starts_with("lib") && file.ends_with(".rlib") { - return true - } else { - let (ref prefix, ref suffix) = dylibname; - if file.starts_with(&prefix[..]) && - file.ends_with(&suffix[..]) { - return true - } - } - sess.err(&format!("extern location for {} is of an unknown type: {}", - self.crate_name, loc.display())); - false - }); - - // Now that we have an iterator of good candidates, make sure - // there's at most one rlib and at most one dylib. - for loc in locs { - if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") { - rlibs.insert(fs::canonicalize(&loc).unwrap(), - PathKind::ExternFlag); - } else { - dylibs.insert(fs::canonicalize(&loc).unwrap(), - PathKind::ExternFlag); - } - } - }; - - // Extract the rlib/dylib pair. - let mut metadata = None; - let rlib = self.extract_one(rlibs, "rlib", &mut metadata); - let dylib = self.extract_one(dylibs, "dylib", &mut metadata); - - if rlib.is_none() && dylib.is_none() { return None } - match metadata { - Some(metadata) => Some(Library { - dylib: dylib, - rlib: rlib, - metadata: metadata, - }), - None => None, - } - } -} - -pub fn note_crate_name(diag: &SpanHandler, name: &str) { - diag.handler().note(&format!("crate name: {}", name)); -} - -impl ArchiveMetadata { - fn new(ar: ArchiveRO) -> Option { - let data = { - let section = ar.iter().find(|sect| { - sect.name() == Some(METADATA_FILENAME) - }); - match section { - Some(s) => s.data() as *const [u8], - None => { - debug!("didn't find '{}' in the archive", METADATA_FILENAME); - return None; - } - } - }; - - Some(ArchiveMetadata { - _archive: ar, - data: data, - }) - } - - pub fn as_slice<'a>(&'a self) -> &'a [u8] { unsafe { &*self.data } } -} - -// Just a small wrapper to time how long reading metadata takes. -fn get_metadata_section(target: &Target, filename: &Path) - -> Result { - let mut ret = None; - let dur = Duration::span(|| { - ret = Some(get_metadata_section_imp(target, filename)); - }); - info!("reading {:?} => {:?}", filename.file_name().unwrap(), dur); - ret.unwrap() -} - -fn get_metadata_section_imp(target: &Target, filename: &Path) - -> Result { - if !filename.exists() { - return Err(format!("no such file: '{}'", filename.display())); - } - if filename.file_name().unwrap().to_str().unwrap().ends_with(".rlib") { - // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap - // internally to read the file. We also avoid even using a memcpy by - // just keeping the archive along while the metadata is in use. - let archive = match ArchiveRO::open(filename) { - Some(ar) => ar, - None => { - debug!("llvm didn't like `{}`", filename.display()); - return Err(format!("failed to read rlib metadata: '{}'", - filename.display())); - } - }; - return match ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)) { - None => Err(format!("failed to read rlib metadata: '{}'", - filename.display())), - Some(blob) => Ok(blob) - }; - } - unsafe { - let buf = common::path2cstr(filename); - let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); - if mb as isize == 0 { - return Err(format!("error reading library: '{}'", - filename.display())) - } - let of = match ObjectFile::new(mb) { - Some(of) => of, - _ => { - return Err((format!("provided path not an object file: '{}'", - filename.display()))) - } - }; - let si = mk_section_iter(of.llof); - while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { - let mut name_buf = ptr::null(); - let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); - let name = slice::from_raw_parts(name_buf as *const u8, - name_len as usize).to_vec(); - let name = String::from_utf8(name).unwrap(); - debug!("get_metadata_section: name {}", name); - if read_meta_section_name(target) == name { - let cbuf = llvm::LLVMGetSectionContents(si.llsi); - let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; - let cvbuf: *const u8 = cbuf as *const u8; - let vlen = encoder::metadata_encoding_version.len(); - debug!("checking {} bytes of metadata-version stamp", - vlen); - let minsz = cmp::min(vlen, csz); - let buf0 = slice::from_raw_parts(cvbuf, minsz); - let version_ok = buf0 == encoder::metadata_encoding_version; - if !version_ok { - return Err((format!("incompatible metadata version found: '{}'", - filename.display()))); - } - - let cvbuf1 = cvbuf.offset(vlen as isize); - debug!("inflating {} bytes of compressed metadata", - csz - vlen); - let bytes = slice::from_raw_parts(cvbuf1, csz - vlen); - match flate::inflate_bytes(bytes) { - Ok(inflated) => return Ok(MetadataVec(inflated)), - Err(_) => {} - } - } - llvm::LLVMMoveToNextSection(si.llsi); - } - Err(format!("metadata not found: '{}'", filename.display())) - } -} - -pub fn meta_section_name(target: &Target) -> &'static str { - if target.options.is_like_osx { - "__DATA,__note.rustc" - } else if target.options.is_like_msvc { - // When using link.exe it was seen that the section name `.note.rustc` - // was getting shortened to `.note.ru`, and according to the PE and COFF - // specification: - // - // > Executable images do not use a string table and do not support - // > section names longer than 8 characters - // - // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx - // - // As a result, we choose a slightly shorter name! As to why - // `.note.rustc` works on MinGW, that's another good question... - ".rustc" - } else { - ".note.rustc" - } -} - -pub fn read_meta_section_name(target: &Target) -> &'static str { - if target.options.is_like_osx { - "__note.rustc" - } else if target.options.is_like_msvc { - ".rustc" - } else { - ".note.rustc" - } -} - -// A diagnostic function for dumping crate metadata to an output stream -pub fn list_file_metadata(target: &Target, path: &Path, - out: &mut io::Write) -> io::Result<()> { - match get_metadata_section(target, path) { - Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out), - Err(msg) => { - write!(out, "{}\n", msg) - } - } -} diff --git a/src/librustc/metadata/macro_import.rs b/src/librustc/metadata/macro_import.rs deleted file mode 100644 index b08f5d0640e..00000000000 --- a/src/librustc/metadata/macro_import.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Used by `rustc` when loading a crate with exported macros. - -use session::Session; -use metadata::creader::CrateReader; -use metadata::cstore::CStore; - -use std::collections::{HashSet, HashMap}; -use syntax::codemap::Span; -use syntax::parse::token; -use syntax::ast; -use syntax::attr; -use syntax::visit; -use syntax::visit::Visitor; -use syntax::attr::AttrMetaMethods; - -struct MacroLoader<'a> { - sess: &'a Session, - span_whitelist: HashSet, - reader: CrateReader<'a>, - macros: Vec, -} - -impl<'a> MacroLoader<'a> { - fn new(sess: &'a Session, cstore: &'a CStore) -> MacroLoader<'a> { - MacroLoader { - sess: sess, - span_whitelist: HashSet::new(), - reader: CrateReader::new(sess, cstore), - macros: vec![], - } - } -} - -pub fn call_bad_macro_reexport(a: &Session, b: Span) { - span_err!(a, b, E0467, "bad macro reexport"); -} - -/// Read exported macros. -pub fn read_macro_defs(sess: &Session, cstore: &CStore, krate: &ast::Crate) - -> Vec -{ - let mut loader = MacroLoader::new(sess, cstore); - - // We need to error on `#[macro_use] extern crate` when it isn't at the - // crate root, because `$crate` won't work properly. Identify these by - // spans, because the crate map isn't set up yet. - for item in &krate.module.items { - if let ast::ItemExternCrate(_) = item.node { - loader.span_whitelist.insert(item.span); - } - } - - visit::walk_crate(&mut loader, krate); - - loader.macros -} - -pub type MacroSelection = HashMap; - -// note that macros aren't expanded yet, and therefore macros can't add macro imports. -impl<'a, 'v> Visitor<'v> for MacroLoader<'a> { - fn visit_item(&mut self, item: &ast::Item) { - // We're only interested in `extern crate`. - match item.node { - ast::ItemExternCrate(_) => {} - _ => { - visit::walk_item(self, item); - return; - } - } - - // Parse the attributes relating to macros. - let mut import = Some(HashMap::new()); // None => load all - let mut reexport = HashMap::new(); - - for attr in &item.attrs { - let mut used = true; - match &attr.name()[..] { - "macro_use" => { - let names = attr.meta_item_list(); - if names.is_none() { - // no names => load all - import = None; - } - if let (Some(sel), Some(names)) = (import.as_mut(), names) { - for attr in names { - if let ast::MetaWord(ref name) = attr.node { - sel.insert(name.clone(), attr.span); - } else { - span_err!(self.sess, attr.span, E0466, "bad macro import"); - } - } - } - } - "macro_reexport" => { - let names = match attr.meta_item_list() { - Some(names) => names, - None => { - call_bad_macro_reexport(self.sess, attr.span); - continue; - } - }; - - for attr in names { - if let ast::MetaWord(ref name) = attr.node { - reexport.insert(name.clone(), attr.span); - } else { - call_bad_macro_reexport(self.sess, attr.span); - } - } - } - _ => used = false, - } - if used { - attr::mark_used(attr); - } - } - - self.load_macros(item, import, reexport) - } - - fn visit_mac(&mut self, _: &ast::Mac) { - // bummer... can't see macro imports inside macros. - // do nothing. - } -} - -impl<'a> MacroLoader<'a> { - fn load_macros<'b>(&mut self, - vi: &ast::Item, - import: Option, - reexport: MacroSelection) { - if let Some(sel) = import.as_ref() { - if sel.is_empty() && reexport.is_empty() { - return; - } - } - - if !self.span_whitelist.contains(&vi.span) { - span_err!(self.sess, vi.span, E0468, - "an `extern crate` loading macros must be at the crate root"); - return; - } - - let macros = self.reader.read_exported_macros(vi); - let mut seen = HashSet::new(); - - for mut def in macros { - let name = def.ident.name.as_str(); - - def.use_locally = match import.as_ref() { - None => true, - Some(sel) => sel.contains_key(&name), - }; - def.export = reexport.contains_key(&name); - def.allow_internal_unstable = attr::contains_name(&def.attrs, - "allow_internal_unstable"); - debug!("load_macros: loaded: {:?}", def); - self.macros.push(def); - seen.insert(name); - } - - if let Some(sel) = import.as_ref() { - for (name, span) in sel { - if !seen.contains(&name) { - span_err!(self.sess, *span, E0469, - "imported macro not found"); - } - } - } - - for (name, span) in &reexport { - if !seen.contains(&name) { - span_err!(self.sess, *span, E0470, - "reexported macro not found"); - } - } - } -} diff --git a/src/librustc/metadata/mod.rs b/src/librustc/metadata/mod.rs deleted file mode 100644 index 052ed81394b..00000000000 --- a/src/librustc/metadata/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub mod common; -pub mod tyencode; -pub mod tydecode; -pub mod encoder; -pub mod decoder; -pub mod creader; -pub mod cstore; -pub mod index; -pub mod loader; -pub mod filesearch; -pub mod macro_import; -pub mod inline; -pub mod util; diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs deleted file mode 100644 index d03af6b6722..00000000000 --- a/src/librustc/metadata/tydecode.rs +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -// Type decoding - -// tjc note: Would be great to have a `match check` macro equivalent -// for some of these - -#![allow(non_camel_case_types)] - -use rustc_front::hir; - -use middle::def_id::{DefId, DefIndex}; -use middle::region; -use middle::subst; -use middle::subst::VecPerParamSpace; -use middle::ty::{self, ToPredicate, Ty, HasTypeFlags}; - -use rbml; -use std::str; -use syntax::abi; -use syntax::ast; -use syntax::parse::token; - -// Compact string representation for Ty values. API TyStr & -// parse_from_str. Extra parameters are for converting to/from def_ids in the -// data buffer. Whatever format you choose should not contain pipe characters. - -pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId; - -pub struct TyDecoder<'a, 'tcx: 'a> { - data: &'a [u8], - krate: ast::CrateNum, - pos: usize, - tcx: &'a ty::ctxt<'tcx>, - conv_def_id: DefIdConvert<'a>, -} - -impl<'a,'tcx> TyDecoder<'a,'tcx> { - pub fn with_doc(tcx: &'a ty::ctxt<'tcx>, - crate_num: ast::CrateNum, - doc: rbml::Doc<'a>, - conv: DefIdConvert<'a>) - -> TyDecoder<'a,'tcx> { - TyDecoder::new(doc.data, crate_num, doc.start, tcx, conv) - } - - pub fn new(data: &'a [u8], - crate_num: ast::CrateNum, - pos: usize, - tcx: &'a ty::ctxt<'tcx>, - conv: DefIdConvert<'a>) - -> TyDecoder<'a, 'tcx> { - TyDecoder { - data: data, - krate: crate_num, - pos: pos, - tcx: tcx, - conv_def_id: conv, - } - } - - fn peek(&self) -> char { - self.data[self.pos] as char - } - - fn next(&mut self) -> char { - let ch = self.data[self.pos] as char; - self.pos = self.pos + 1; - return ch; - } - - fn next_byte(&mut self) -> u8 { - let b = self.data[self.pos]; - self.pos = self.pos + 1; - return b; - } - - fn scan(&mut self, mut is_last: F) -> &'a [u8] - where F: FnMut(char) -> bool, - { - let start_pos = self.pos; - debug!("scan: '{}' (start)", self.data[self.pos] as char); - while !is_last(self.data[self.pos] as char) { - self.pos += 1; - debug!("scan: '{}'", self.data[self.pos] as char); - } - let end_pos = self.pos; - self.pos += 1; - return &self.data[start_pos..end_pos]; - } - - fn parse_vuint(&mut self) -> usize { - let res = rbml::reader::vuint_at(self.data, self.pos).unwrap(); - self.pos = res.next; - res.val - } - - fn parse_name(&mut self, last: char) -> ast::Name { - fn is_last(b: char, c: char) -> bool { return c == b; } - let bytes = self.scan(|a| is_last(last, a)); - token::intern(str::from_utf8(bytes).unwrap()) - } - - fn parse_size(&mut self) -> Option { - assert_eq!(self.next(), '/'); - - if self.peek() == '|' { - assert_eq!(self.next(), '|'); - None - } else { - let n = self.parse_uint(); - assert_eq!(self.next(), '|'); - Some(n) - } - } - - fn parse_vec_per_param_space(&mut self, mut f: F) -> VecPerParamSpace where - F: FnMut(&mut TyDecoder<'a, 'tcx>) -> T, - { - let mut r = VecPerParamSpace::empty(); - for &space in &subst::ParamSpace::all() { - assert_eq!(self.next(), '['); - while self.peek() != ']' { - r.push(space, f(self)); - } - assert_eq!(self.next(), ']'); - } - r - } - - pub fn parse_substs(&mut self) -> subst::Substs<'tcx> { - let regions = self.parse_region_substs(); - let types = self.parse_vec_per_param_space(|this| this.parse_ty()); - subst::Substs { types: types, regions: regions } - } - - fn parse_region_substs(&mut self) -> subst::RegionSubsts { - match self.next() { - 'e' => subst::ErasedRegions, - 'n' => { - subst::NonerasedRegions( - self.parse_vec_per_param_space(|this| this.parse_region())) - } - _ => panic!("parse_bound_region: bad input") - } - } - - fn parse_bound_region(&mut self) -> ty::BoundRegion { - match self.next() { - 'a' => { - let id = self.parse_u32(); - assert_eq!(self.next(), '|'); - ty::BrAnon(id) - } - '[' => { - let def = self.parse_def(); - let name = token::intern(&self.parse_str(']')); - ty::BrNamed(def, name) - } - 'f' => { - let id = self.parse_u32(); - assert_eq!(self.next(), '|'); - ty::BrFresh(id) - } - 'e' => ty::BrEnv, - _ => panic!("parse_bound_region: bad input") - } - } - - pub fn parse_region(&mut self) -> ty::Region { - match self.next() { - 'b' => { - assert_eq!(self.next(), '['); - let id = ty::DebruijnIndex::new(self.parse_u32()); - assert_eq!(self.next(), '|'); - let br = self.parse_bound_region(); - assert_eq!(self.next(), ']'); - ty::ReLateBound(id, br) - } - 'B' => { - assert_eq!(self.next(), '['); - let def_id = self.parse_def(); - let space = self.parse_param_space(); - assert_eq!(self.next(), '|'); - let index = self.parse_u32(); - assert_eq!(self.next(), '|'); - let name = token::intern(&self.parse_str(']')); - ty::ReEarlyBound(ty::EarlyBoundRegion { - def_id: def_id, - space: space, - index: index, - name: name - }) - } - 'f' => { - assert_eq!(self.next(), '['); - let scope = self.parse_scope(); - assert_eq!(self.next(), '|'); - let br = self.parse_bound_region(); - assert_eq!(self.next(), ']'); - ty::ReFree(ty::FreeRegion { scope: scope, - bound_region: br}) - } - 's' => { - let scope = self.parse_scope(); - assert_eq!(self.next(), '|'); - ty::ReScope(scope) - } - 't' => { - ty::ReStatic - } - 'e' => { - ty::ReStatic - } - _ => panic!("parse_region: bad input") - } - } - - fn parse_scope(&mut self) -> region::CodeExtent { - self.tcx.region_maps.bogus_code_extent(match self.next() { - // This creates scopes with the wrong NodeId. This isn't - // actually a problem because scopes only exist *within* - // functions, and functions aren't loaded until trans which - // doesn't care about regions. - // - // May still be worth fixing though. - 'P' => { - assert_eq!(self.next(), '['); - let fn_id = self.parse_uint() as ast::NodeId; - assert_eq!(self.next(), '|'); - let body_id = self.parse_uint() as ast::NodeId; - assert_eq!(self.next(), ']'); - region::CodeExtentData::ParameterScope { - fn_id: fn_id, body_id: body_id - } - } - 'M' => { - let node_id = self.parse_uint() as ast::NodeId; - region::CodeExtentData::Misc(node_id) - } - 'D' => { - let node_id = self.parse_uint() as ast::NodeId; - region::CodeExtentData::DestructionScope(node_id) - } - 'B' => { - assert_eq!(self.next(), '['); - let node_id = self.parse_uint() as ast::NodeId; - assert_eq!(self.next(), '|'); - let first_stmt_index = self.parse_u32(); - assert_eq!(self.next(), ']'); - let block_remainder = region::BlockRemainder { - block: node_id, first_statement_index: first_stmt_index, - }; - region::CodeExtentData::Remainder(block_remainder) - } - _ => panic!("parse_scope: bad input") - }) - } - - fn parse_opt(&mut self, f: F) -> Option - where F: FnOnce(&mut TyDecoder<'a, 'tcx>) -> T, - { - match self.next() { - 'n' => None, - 's' => Some(f(self)), - _ => panic!("parse_opt: bad input") - } - } - - fn parse_str(&mut self, term: char) -> String { - let mut result = String::new(); - while self.peek() != term { - unsafe { - result.as_mut_vec().push_all(&[self.next_byte()]) - } - } - self.next(); - result - } - - pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> { - let def = self.parse_def(); - let substs = self.tcx.mk_substs(self.parse_substs()); - ty::TraitRef {def_id: def, substs: substs} - } - - pub fn parse_ty(&mut self) -> Ty<'tcx> { - let tcx = self.tcx; - match self.next() { - 'b' => return tcx.types.bool, - 'i' => { /* eat the s of is */ self.next(); return tcx.types.isize }, - 'u' => { /* eat the s of us */ self.next(); return tcx.types.usize }, - 'M' => { - match self.next() { - 'b' => return tcx.types.u8, - 'w' => return tcx.types.u16, - 'l' => return tcx.types.u32, - 'd' => return tcx.types.u64, - 'B' => return tcx.types.i8, - 'W' => return tcx.types.i16, - 'L' => return tcx.types.i32, - 'D' => return tcx.types.i64, - 'f' => return tcx.types.f32, - 'F' => return tcx.types.f64, - _ => panic!("parse_ty: bad numeric type") - } - } - 'c' => return tcx.types.char, - 't' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return tcx.mk_enum(def, self.tcx.mk_substs(substs)); - } - 'x' => { - assert_eq!(self.next(), '['); - let trait_ref = ty::Binder(self.parse_trait_ref()); - let bounds = self.parse_existential_bounds(); - assert_eq!(self.next(), ']'); - return tcx.mk_trait(trait_ref, bounds); - } - 'p' => { - assert_eq!(self.next(), '['); - let index = self.parse_u32(); - assert_eq!(self.next(), '|'); - let space = self.parse_param_space(); - assert_eq!(self.next(), '|'); - let name = token::intern(&self.parse_str(']')); - return tcx.mk_param(space, index, name); - } - '~' => return tcx.mk_box(self.parse_ty()), - '*' => return tcx.mk_ptr(self.parse_mt()), - '&' => { - let r = self.parse_region(); - let mt = self.parse_mt(); - return tcx.mk_ref(tcx.mk_region(r), mt); - } - 'V' => { - let t = self.parse_ty(); - return match self.parse_size() { - Some(n) => tcx.mk_array(t, n), - None => tcx.mk_slice(t) - }; - } - 'v' => { - return tcx.mk_str(); - } - 'T' => { - assert_eq!(self.next(), '['); - let mut params = Vec::new(); - while self.peek() != ']' { params.push(self.parse_ty()); } - self.pos = self.pos + 1; - return tcx.mk_tup(params); - } - 'F' => { - let def_id = self.parse_def(); - return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(self.parse_bare_fn_ty())); - } - 'G' => { - return tcx.mk_fn(None, tcx.mk_bare_fn(self.parse_bare_fn_ty())); - } - '#' => { - // This is a hacky little caching scheme. The idea is that if we encode - // the same type twice, the second (and third, and fourth...) time we will - // just write `#123`, where `123` is the offset in the metadata of the - // first appearance. Now when we are *decoding*, if we see a `#123`, we - // can first check a cache (`tcx.rcache`) for that offset. If we find something, - // we return it (modulo closure types, see below). But if not, then we - // jump to offset 123 and read the type from there. - - let pos = self.parse_vuint(); - let key = ty::CReaderCacheKey { cnum: self.krate, pos: pos }; - match tcx.rcache.borrow().get(&key).cloned() { - Some(tt) => { - // If there is a closure buried in the type some where, then we - // need to re-convert any def ids (see case 'k', below). That means - // we can't reuse the cached version. - if !tt.has_closure_types() { - return tt; - } - } - None => {} - } - - let mut substate = TyDecoder::new(self.data, - self.krate, - pos, - self.tcx, - self.conv_def_id); - let tt = substate.parse_ty(); - tcx.rcache.borrow_mut().insert(key, tt); - return tt; - } - '\"' => { - let _ = self.parse_def(); - let inner = self.parse_ty(); - inner - } - 'a' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_struct(def, self.tcx.mk_substs(substs)); - } - 'k' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - let mut tys = vec![]; - while self.peek() != '.' { - tys.push(self.parse_ty()); - } - assert_eq!(self.next(), '.'); - assert_eq!(self.next(), ']'); - return self.tcx.mk_closure(did, self.tcx.mk_substs(substs), tys); - } - 'P' => { - assert_eq!(self.next(), '['); - let trait_ref = self.parse_trait_ref(); - let name = token::intern(&self.parse_str(']')); - return tcx.mk_projection(trait_ref, name); - } - 'e' => { - return tcx.types.err; - } - c => { panic!("unexpected char in type string: {}", c);} - } - } - - fn parse_mutability(&mut self) -> hir::Mutability { - match self.peek() { - 'm' => { self.next(); hir::MutMutable } - _ => { hir::MutImmutable } - } - } - - fn parse_mt(&mut self) -> ty::TypeAndMut<'tcx> { - let m = self.parse_mutability(); - ty::TypeAndMut { ty: self.parse_ty(), mutbl: m } - } - - fn parse_def(&mut self) -> DefId { - let def_id = parse_defid(self.scan(|c| c == '|')); - return (self.conv_def_id)(def_id); - } - - fn parse_uint(&mut self) -> usize { - let mut n = 0; - loop { - let cur = self.peek(); - if cur < '0' || cur > '9' { return n; } - self.pos = self.pos + 1; - n *= 10; - n += (cur as usize) - ('0' as usize); - }; - } - - fn parse_u32(&mut self) -> u32 { - let n = self.parse_uint(); - let m = n as u32; - assert_eq!(m as usize, n); - m - } - - fn parse_param_space(&mut self) -> subst::ParamSpace { - subst::ParamSpace::from_uint(self.parse_uint()) - } - - fn parse_abi_set(&mut self) -> abi::Abi { - assert_eq!(self.next(), '['); - let bytes = self.scan(|c| c == ']'); - let abi_str = str::from_utf8(bytes).unwrap(); - abi::lookup(&abi_str[..]).expect(abi_str) - } - - pub fn parse_closure_ty(&mut self) -> ty::ClosureTy<'tcx> { - let unsafety = parse_unsafety(self.next()); - let sig = self.parse_sig(); - let abi = self.parse_abi_set(); - ty::ClosureTy { - unsafety: unsafety, - sig: sig, - abi: abi, - } - } - - pub fn parse_bare_fn_ty(&mut self) -> ty::BareFnTy<'tcx> { - let unsafety = parse_unsafety(self.next()); - let abi = self.parse_abi_set(); - let sig = self.parse_sig(); - ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: sig - } - } - - fn parse_sig(&mut self) -> ty::PolyFnSig<'tcx> { - assert_eq!(self.next(), '['); - let mut inputs = Vec::new(); - while self.peek() != ']' { - inputs.push(self.parse_ty()); - } - self.pos += 1; // eat the ']' - let variadic = match self.next() { - 'V' => true, - 'N' => false, - r => panic!(format!("bad variadic: {}", r)), - }; - let output = match self.peek() { - 'z' => { - self.pos += 1; - ty::FnDiverging - } - _ => ty::FnConverging(self.parse_ty()) - }; - ty::Binder(ty::FnSig {inputs: inputs, - output: output, - variadic: variadic}) - } - - pub fn parse_predicate(&mut self) -> ty::Predicate<'tcx> { - match self.next() { - 't' => ty::Binder(self.parse_trait_ref()).to_predicate(), - 'e' => ty::Binder(ty::EquatePredicate(self.parse_ty(), - self.parse_ty())).to_predicate(), - 'r' => ty::Binder(ty::OutlivesPredicate(self.parse_region(), - self.parse_region())).to_predicate(), - 'o' => ty::Binder(ty::OutlivesPredicate(self.parse_ty(), - self.parse_region())).to_predicate(), - 'p' => ty::Binder(self.parse_projection_predicate()).to_predicate(), - 'w' => ty::Predicate::WellFormed(self.parse_ty()), - 'O' => { - let def_id = self.parse_def(); - assert_eq!(self.next(), '|'); - ty::Predicate::ObjectSafe(def_id) - } - c => panic!("Encountered invalid character in metadata: {}", c) - } - } - - fn parse_projection_predicate(&mut self) -> ty::ProjectionPredicate<'tcx> { - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - trait_ref: self.parse_trait_ref(), - item_name: token::intern(&self.parse_str('|')), - }, - ty: self.parse_ty(), - } - } - - pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { - let name = self.parse_name(':'); - let def_id = self.parse_def(); - let space = self.parse_param_space(); - assert_eq!(self.next(), '|'); - let index = self.parse_u32(); - assert_eq!(self.next(), '|'); - let default_def_id = self.parse_def(); - let default = self.parse_opt(|this| this.parse_ty()); - let object_lifetime_default = self.parse_object_lifetime_default(); - - ty::TypeParameterDef { - name: name, - def_id: def_id, - space: space, - index: index, - default_def_id: default_def_id, - default: default, - object_lifetime_default: object_lifetime_default, - } - } - - pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { - let name = self.parse_name(':'); - let def_id = self.parse_def(); - let space = self.parse_param_space(); - assert_eq!(self.next(), '|'); - let index = self.parse_u32(); - assert_eq!(self.next(), '|'); - let mut bounds = vec![]; - loop { - match self.next() { - 'R' => bounds.push(self.parse_region()), - '.' => { break; } - c => { - panic!("parse_region_param_def: bad bounds ('{}')", c) - } - } - } - ty::RegionParameterDef { - name: name, - def_id: def_id, - space: space, - index: index, - bounds: bounds - } - } - - - fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault { - match self.next() { - 'a' => ty::ObjectLifetimeDefault::Ambiguous, - 'b' => ty::ObjectLifetimeDefault::BaseDefault, - 's' => { - let region = self.parse_region(); - ty::ObjectLifetimeDefault::Specific(region) - } - _ => panic!("parse_object_lifetime_default: bad input") - } - } - - pub fn parse_existential_bounds(&mut self) -> ty::ExistentialBounds<'tcx> { - let builtin_bounds = self.parse_builtin_bounds(); - let region_bound = self.parse_region(); - let mut projection_bounds = Vec::new(); - - loop { - match self.next() { - 'P' => { - projection_bounds.push(ty::Binder(self.parse_projection_predicate())); - } - '.' => { break; } - c => { - panic!("parse_bounds: bad bounds ('{}')", c) - } - } - } - - ty::ExistentialBounds::new( - region_bound, builtin_bounds, projection_bounds) - } - - fn parse_builtin_bounds(&mut self) -> ty::BuiltinBounds { - let mut builtin_bounds = ty::BuiltinBounds::empty(); - loop { - match self.next() { - 'S' => { - builtin_bounds.insert(ty::BoundSend); - } - 'Z' => { - builtin_bounds.insert(ty::BoundSized); - } - 'P' => { - builtin_bounds.insert(ty::BoundCopy); - } - 'T' => { - builtin_bounds.insert(ty::BoundSync); - } - '.' => { - return builtin_bounds; - } - c => { - panic!("parse_bounds: bad builtin bounds ('{}')", c) - } - } - } - } -} - -// Rust metadata parsing -fn parse_defid(buf: &[u8]) -> DefId { - let mut colon_idx = 0; - let len = buf.len(); - while colon_idx < len && buf[colon_idx] != ':' as u8 { colon_idx += 1; } - if colon_idx == len { - error!("didn't find ':' when parsing def id"); - panic!(); - } - - let crate_part = &buf[0..colon_idx]; - let def_part = &buf[colon_idx + 1..len]; - - let crate_num = match str::from_utf8(crate_part).ok().and_then(|s| { - s.parse::().ok() - }) { - Some(cn) => cn as ast::CrateNum, - None => panic!("internal error: parse_defid: crate number expected, found {:?}", - crate_part) - }; - let def_num = match str::from_utf8(def_part).ok().and_then(|s| { - s.parse::().ok() - }) { - Some(dn) => dn, - None => panic!("internal error: parse_defid: id expected, found {:?}", - def_part) - }; - let index = DefIndex::new(def_num); - DefId { krate: crate_num, index: index } -} - -fn parse_unsafety(c: char) -> hir::Unsafety { - match c { - 'u' => hir::Unsafety::Unsafe, - 'n' => hir::Unsafety::Normal, - _ => panic!("parse_unsafety: bad unsafety {}", c) - } -} diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs deleted file mode 100644 index 1b993a00e28..00000000000 --- a/src/librustc/metadata/tyencode.rs +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Type encoding - -#![allow(unused_must_use)] // as with encoding, everything is a no-fail MemWriter -#![allow(non_camel_case_types)] - -use std::cell::RefCell; -use std::io::Cursor; -use std::io::prelude::*; - -use middle::def_id::DefId; -use middle::region; -use middle::subst; -use middle::subst::VecPerParamSpace; -use middle::ty::ParamTy; -use middle::ty::{self, Ty}; -use util::nodemap::FnvHashMap; - -use rustc_front::hir; - -use syntax::abi::Abi; -use syntax::ast; -use syntax::diagnostic::SpanHandler; - -use rbml::writer::{self, Encoder}; - -macro_rules! mywrite { ($w:expr, $($arg:tt)*) => ({ write!($w.writer, $($arg)*); }) } - -pub struct ctxt<'a, 'tcx: 'a> { - pub diag: &'a SpanHandler, - // Def -> str Callback: - pub ds: fn(DefId) -> String, - // The type context. - pub tcx: &'a ty::ctxt<'tcx>, - pub abbrevs: &'a abbrev_map<'tcx> -} - -// Compact string representation for Ty values. API TyStr & parse_from_str. -// Extra parameters are for converting to/from def_ids in the string rep. -// Whatever format you choose should not contain pipe characters. -pub struct ty_abbrev { - s: Vec -} - -pub type abbrev_map<'tcx> = RefCell, ty_abbrev>>; - -pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { - match cx.abbrevs.borrow_mut().get(&t) { - Some(a) => { w.writer.write_all(&a.s); return; } - None => {} - } - - // type abbreviations needs a stable position - let pos = w.mark_stable_position(); - - match t.sty { - ty::TyBool => mywrite!(w, "b"), - ty::TyChar => mywrite!(w, "c"), - ty::TyInt(t) => { - match t { - ast::TyIs => mywrite!(w, "is"), - ast::TyI8 => mywrite!(w, "MB"), - ast::TyI16 => mywrite!(w, "MW"), - ast::TyI32 => mywrite!(w, "ML"), - ast::TyI64 => mywrite!(w, "MD") - } - } - ty::TyUint(t) => { - match t { - ast::TyUs => mywrite!(w, "us"), - ast::TyU8 => mywrite!(w, "Mb"), - ast::TyU16 => mywrite!(w, "Mw"), - ast::TyU32 => mywrite!(w, "Ml"), - ast::TyU64 => mywrite!(w, "Md") - } - } - ty::TyFloat(t) => { - match t { - ast::TyF32 => mywrite!(w, "Mf"), - ast::TyF64 => mywrite!(w, "MF"), - } - } - ty::TyEnum(def, substs) => { - mywrite!(w, "t[{}|", (cx.ds)(def.did)); - enc_substs(w, cx, substs); - mywrite!(w, "]"); - } - ty::TyTrait(box ty::TraitTy { ref principal, - ref bounds }) => { - mywrite!(w, "x["); - enc_trait_ref(w, cx, principal.0); - enc_existential_bounds(w, cx, bounds); - mywrite!(w, "]"); - } - ty::TyTuple(ref ts) => { - mywrite!(w, "T["); - for t in ts { enc_ty(w, cx, *t); } - mywrite!(w, "]"); - } - ty::TyBox(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); } - ty::TyRawPtr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); } - ty::TyRef(r, mt) => { - mywrite!(w, "&"); - enc_region(w, cx, *r); - enc_mt(w, cx, mt); - } - ty::TyArray(t, sz) => { - mywrite!(w, "V"); - enc_ty(w, cx, t); - mywrite!(w, "/{}|", sz); - } - ty::TySlice(t) => { - mywrite!(w, "V"); - enc_ty(w, cx, t); - mywrite!(w, "/|"); - } - ty::TyStr => { - mywrite!(w, "v"); - } - ty::TyBareFn(Some(def_id), f) => { - mywrite!(w, "F"); - mywrite!(w, "{}|", (cx.ds)(def_id)); - enc_bare_fn_ty(w, cx, f); - } - ty::TyBareFn(None, f) => { - mywrite!(w, "G"); - enc_bare_fn_ty(w, cx, f); - } - ty::TyInfer(_) => { - cx.diag.handler().bug("cannot encode inference variable types"); - } - ty::TyParam(ParamTy {space, idx, name}) => { - mywrite!(w, "p[{}|{}|{}]", idx, space.to_uint(), name) - } - ty::TyStruct(def, substs) => { - mywrite!(w, "a[{}|", (cx.ds)(def.did)); - enc_substs(w, cx, substs); - mywrite!(w, "]"); - } - ty::TyClosure(def, ref substs) => { - mywrite!(w, "k[{}|", (cx.ds)(def)); - enc_substs(w, cx, &substs.func_substs); - for ty in &substs.upvar_tys { - enc_ty(w, cx, ty); - } - mywrite!(w, "."); - mywrite!(w, "]"); - } - ty::TyProjection(ref data) => { - mywrite!(w, "P["); - enc_trait_ref(w, cx, data.trait_ref); - mywrite!(w, "{}]", data.item_name); - } - ty::TyError => { - mywrite!(w, "e"); - } - } - - let end = w.mark_stable_position(); - let len = end - pos; - - let buf: &mut [u8] = &mut [0; 16]; // vuint < 15 bytes - let mut abbrev = Cursor::new(buf); - abbrev.write_all(b"#"); - writer::write_vuint(&mut abbrev, pos as usize); - - cx.abbrevs.borrow_mut().insert(t, ty_abbrev { - s: if abbrev.position() < len { - abbrev.get_ref()[..abbrev.position() as usize].to_owned() - } else { - // if the abbreviation is longer than the real type, - // don't use #-notation. However, insert it here so - // other won't have to `mark_stable_position` - w.writer.get_ref()[pos as usize..end as usize].to_owned() - } - }); -} - -fn enc_mutability(w: &mut Encoder, mt: hir::Mutability) { - match mt { - hir::MutImmutable => (), - hir::MutMutable => mywrite!(w, "m"), - } -} - -fn enc_mt<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, - mt: ty::TypeAndMut<'tcx>) { - enc_mutability(w, mt.mutbl); - enc_ty(w, cx, mt.ty); -} - -fn enc_opt(w: &mut Encoder, t: Option, enc_f: F) where - F: FnOnce(&mut Encoder, T), -{ - match t { - None => mywrite!(w, "n"), - Some(v) => { - mywrite!(w, "s"); - enc_f(w, v); - } - } -} - -fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut Encoder, - cx: &ctxt<'a, 'tcx>, - v: &VecPerParamSpace, - mut op: F) where - F: FnMut(&mut Encoder, &ctxt<'a, 'tcx>, &T), -{ - for &space in &subst::ParamSpace::all() { - mywrite!(w, "["); - for t in v.get_slice(space) { - op(w, cx, t); - } - mywrite!(w, "]"); - } -} - -pub fn enc_substs<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, - substs: &subst::Substs<'tcx>) { - enc_region_substs(w, cx, &substs.regions); - enc_vec_per_param_space(w, cx, &substs.types, - |w, cx, &ty| enc_ty(w, cx, ty)); -} - -fn enc_region_substs(w: &mut Encoder, cx: &ctxt, substs: &subst::RegionSubsts) { - match *substs { - subst::ErasedRegions => { - mywrite!(w, "e"); - } - subst::NonerasedRegions(ref regions) => { - mywrite!(w, "n"); - enc_vec_per_param_space(w, cx, regions, - |w, cx, &r| enc_region(w, cx, r)); - } - } -} - -pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { - match r { - ty::ReLateBound(id, br) => { - mywrite!(w, "b[{}|", id.depth); - enc_bound_region(w, cx, br); - mywrite!(w, "]"); - } - ty::ReEarlyBound(ref data) => { - mywrite!(w, "B[{}|{}|{}|{}]", - (cx.ds)(data.def_id), - data.space.to_uint(), - data.index, - data.name); - } - ty::ReFree(ref fr) => { - mywrite!(w, "f["); - enc_scope(w, cx, fr.scope); - mywrite!(w, "|"); - enc_bound_region(w, cx, fr.bound_region); - mywrite!(w, "]"); - } - ty::ReScope(scope) => { - mywrite!(w, "s"); - enc_scope(w, cx, scope); - mywrite!(w, "|"); - } - ty::ReStatic => { - mywrite!(w, "t"); - } - ty::ReEmpty => { - mywrite!(w, "e"); - } - ty::ReVar(_) | ty::ReSkolemized(..) => { - // these should not crop up after typeck - cx.diag.handler().bug("cannot encode region variables"); - } - } -} - -fn enc_scope(w: &mut Encoder, cx: &ctxt, scope: region::CodeExtent) { - match cx.tcx.region_maps.code_extent_data(scope) { - region::CodeExtentData::ParameterScope { - fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id), - region::CodeExtentData::Misc(node_id) => mywrite!(w, "M{}", node_id), - region::CodeExtentData::Remainder(region::BlockRemainder { - block: b, first_statement_index: i }) => mywrite!(w, "B[{}|{}]", b, i), - region::CodeExtentData::DestructionScope(node_id) => mywrite!(w, "D{}", node_id), - } -} - -fn enc_bound_region(w: &mut Encoder, cx: &ctxt, br: ty::BoundRegion) { - match br { - ty::BrAnon(idx) => { - mywrite!(w, "a{}|", idx); - } - ty::BrNamed(d, name) => { - mywrite!(w, "[{}|{}]", - (cx.ds)(d), - name); - } - ty::BrFresh(id) => { - mywrite!(w, "f{}|", id); - } - ty::BrEnv => { - mywrite!(w, "e|"); - } - } -} - -pub fn enc_trait_ref<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, - s: ty::TraitRef<'tcx>) { - mywrite!(w, "{}|", (cx.ds)(s.def_id)); - enc_substs(w, cx, s.substs); -} - -fn enc_unsafety(w: &mut Encoder, p: hir::Unsafety) { - match p { - hir::Unsafety::Normal => mywrite!(w, "n"), - hir::Unsafety::Unsafe => mywrite!(w, "u"), - } -} - -fn enc_abi(w: &mut Encoder, abi: Abi) { - mywrite!(w, "["); - mywrite!(w, "{}", abi.name()); - mywrite!(w, "]") -} - -pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, - ft: &ty::BareFnTy<'tcx>) { - enc_unsafety(w, ft.unsafety); - enc_abi(w, ft.abi); - enc_fn_sig(w, cx, &ft.sig); -} - -pub fn enc_closure_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, - ft: &ty::ClosureTy<'tcx>) { - enc_unsafety(w, ft.unsafety); - enc_fn_sig(w, cx, &ft.sig); - enc_abi(w, ft.abi); -} - -fn enc_fn_sig<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, - fsig: &ty::PolyFnSig<'tcx>) { - mywrite!(w, "["); - for ty in &fsig.0.inputs { - enc_ty(w, cx, *ty); - } - mywrite!(w, "]"); - if fsig.0.variadic { - mywrite!(w, "V"); - } else { - mywrite!(w, "N"); - } - match fsig.0.output { - ty::FnConverging(result_type) => { - enc_ty(w, cx, result_type); - } - ty::FnDiverging => { - mywrite!(w, "z"); - } - } -} - -pub fn enc_builtin_bounds(w: &mut Encoder, _cx: &ctxt, bs: &ty::BuiltinBounds) { - for bound in bs { - match bound { - ty::BoundSend => mywrite!(w, "S"), - ty::BoundSized => mywrite!(w, "Z"), - ty::BoundCopy => mywrite!(w, "P"), - ty::BoundSync => mywrite!(w, "T"), - } - } - - mywrite!(w, "."); -} - -pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder, - cx: &ctxt<'a,'tcx>, - bs: &ty::ExistentialBounds<'tcx>) { - enc_builtin_bounds(w, cx, &bs.builtin_bounds); - - enc_region(w, cx, bs.region_bound); - - for tp in &bs.projection_bounds { - mywrite!(w, "P"); - enc_projection_predicate(w, cx, &tp.0); - } - - mywrite!(w, "."); -} - -pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, - v: &ty::TypeParameterDef<'tcx>) { - mywrite!(w, "{}:{}|{}|{}|{}|", - v.name, (cx.ds)(v.def_id), - v.space.to_uint(), v.index, (cx.ds)(v.default_def_id)); - enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); - enc_object_lifetime_default(w, cx, v.object_lifetime_default); -} - -pub fn enc_region_param_def(w: &mut Encoder, cx: &ctxt, - v: &ty::RegionParameterDef) { - mywrite!(w, "{}:{}|{}|{}|", - v.name, (cx.ds)(v.def_id), - v.space.to_uint(), v.index); - for &r in &v.bounds { - mywrite!(w, "R"); - enc_region(w, cx, r); - } - mywrite!(w, "."); -} - -fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder, - cx: &ctxt<'a, 'tcx>, - default: ty::ObjectLifetimeDefault) -{ - match default { - ty::ObjectLifetimeDefault::Ambiguous => mywrite!(w, "a"), - ty::ObjectLifetimeDefault::BaseDefault => mywrite!(w, "b"), - ty::ObjectLifetimeDefault::Specific(r) => { - mywrite!(w, "s"); - enc_region(w, cx, r); - } - } -} - -pub fn enc_predicate<'a, 'tcx>(w: &mut Encoder, - cx: &ctxt<'a, 'tcx>, - p: &ty::Predicate<'tcx>) -{ - match *p { - ty::Predicate::Trait(ref trait_ref) => { - mywrite!(w, "t"); - enc_trait_ref(w, cx, trait_ref.0.trait_ref); - } - ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => { - mywrite!(w, "e"); - enc_ty(w, cx, a); - enc_ty(w, cx, b); - } - ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { - mywrite!(w, "r"); - enc_region(w, cx, a); - enc_region(w, cx, b); - } - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { - mywrite!(w, "o"); - enc_ty(w, cx, a); - enc_region(w, cx, b); - } - ty::Predicate::Projection(ty::Binder(ref data)) => { - mywrite!(w, "p"); - enc_projection_predicate(w, cx, data) - } - ty::Predicate::WellFormed(data) => { - mywrite!(w, "w"); - enc_ty(w, cx, data); - } - ty::Predicate::ObjectSafe(trait_def_id) => { - mywrite!(w, "O{}|", (cx.ds)(trait_def_id)); - } - } -} - -fn enc_projection_predicate<'a, 'tcx>(w: &mut Encoder, - cx: &ctxt<'a, 'tcx>, - data: &ty::ProjectionPredicate<'tcx>) { - enc_trait_ref(w, cx, data.projection_ty.trait_ref); - mywrite!(w, "{}|", data.projection_ty.item_name); - enc_ty(w, cx, data.ty); -} diff --git a/src/librustc/metadata/util.rs b/src/librustc/metadata/util.rs deleted file mode 100644 index f00dd3b852c..00000000000 --- a/src/librustc/metadata/util.rs +++ /dev/null @@ -1,616 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use back::svh::Svh; -use front::map as ast_map; -use metadata::cstore; -use metadata::decoder; -use metadata::encoder; -use metadata::loader; -use middle::astencode; -use middle::def; -use middle::lang_items; -use middle::ty::{self, Ty}; -use middle::def_id::{DefId, DefIndex}; -use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; - -use std::any::Any; -use std::cell::RefCell; -use std::rc::Rc; -use std::path::PathBuf; -use syntax::ast; -use syntax::attr; -use rustc_back::target::Target; -use rustc_front::hir; - -pub use metadata::common::LinkMeta; -pub use metadata::creader::validate_crate_name; -pub use metadata::cstore::CrateSource; -pub use metadata::cstore::LinkagePreference; -pub use metadata::cstore::NativeLibraryKind; -pub use metadata::decoder::DecodeInlinedItem; -pub use metadata::decoder::DefLike; -pub use metadata::inline::InlinedItem; - -pub use self::DefLike::{DlDef, DlField, DlImpl}; -pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; - -pub struct ChildItem { - pub def: DefLike, - pub name: ast::Name, - pub vis: hir::Visibility -} - -pub enum FoundAst<'ast> { - Found(&'ast InlinedItem), - FoundParent(DefId, &'ast InlinedItem), - NotFound, -} - -pub trait CrateStore<'tcx> : Any { - // item info - fn stability(&self, def: DefId) -> Option; - fn closure_kind(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) - -> ty::ClosureKind; - fn closure_ty(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) - -> ty::ClosureTy<'tcx>; - fn item_variances(&self, def: DefId) -> ty::ItemVariances; - fn repr_attrs(&self, def: DefId) -> Vec; - fn item_type(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::TypeScheme<'tcx>; - fn item_path(&self, def: DefId) -> Vec; - fn item_name(&self, def: DefId) -> ast::Name; - fn item_predicates(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::GenericPredicates<'tcx>; - fn item_super_predicates(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::GenericPredicates<'tcx>; - fn item_attrs(&self, def_id: DefId) -> Vec; - fn item_symbol(&self, def: DefId) -> String; - fn trait_def(&self, tcx: &ty::ctxt<'tcx>, def: DefId)-> ty::TraitDef<'tcx>; - fn adt_def(&self, tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>; - fn method_arg_names(&self, did: DefId) -> Vec; - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec; - - // trait info - fn implementations_of_trait(&self, def_id: DefId) -> Vec; - fn provided_trait_methods(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> Vec>>; - fn trait_item_def_ids(&self, def: DefId) - -> Vec; - - // impl info - fn impl_items(&self, impl_def_id: DefId) -> Vec; - fn impl_trait_ref(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> Option>; - fn impl_polarity(&self, def: DefId) -> Option; - fn custom_coerce_unsized_kind(&self, def: DefId) - -> Option; - fn associated_consts(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> Vec>>; - - // trait/impl-item info - fn trait_of_item(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) - -> Option; - fn impl_or_trait_item(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::ImplOrTraitItem<'tcx>; - - // flags - fn is_const_fn(&self, did: DefId) -> bool; - fn is_defaulted_trait(&self, did: DefId) -> bool; - fn is_impl(&self, did: DefId) -> bool; - fn is_default_impl(&self, impl_did: DefId) -> bool; - fn is_extern_fn(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool; - fn is_static(&self, did: DefId) -> bool; - fn is_static_method(&self, did: DefId) -> bool; - fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; - fn is_typedef(&self, did: DefId) -> bool; - - // crate metadata - fn dylib_dependency_formats(&self, cnum: ast::CrateNum) - -> Vec<(ast::CrateNum, LinkagePreference)>; - fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)>; - fn missing_lang_items(&self, cnum: ast::CrateNum) -> Vec; - fn is_staged_api(&self, cnum: ast::CrateNum) -> bool; - fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; - fn is_allocator(&self, cnum: ast::CrateNum) -> bool; - fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; - fn crate_name(&self, cnum: ast::CrateNum) -> String; - fn crate_hash(&self, cnum: ast::CrateNum) -> Svh; - fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) - -> FnvHashMap>; - fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option; - fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>; - fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec; - - // resolve - fn def_path(&self, def: DefId) -> ast_map::DefPath; - fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; - fn struct_field_names(&self, def: DefId) -> Vec; - fn item_children(&self, did: DefId) -> Vec; - fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec; - - // misc. metadata - fn maybe_get_item_ast(&'tcx self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> FoundAst<'tcx>; - // This is basically a 1-based range of ints, which is a little - // silly - I may fix that. - fn crates(&self) -> Vec; - fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>; - fn used_link_args(&self) -> Vec; - - // utility functions - fn metadata_filename(&self) -> &str; - fn metadata_section_name(&self, target: &Target) -> &str; - fn encode_type(&self, tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Vec; - fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)>; - fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource; - fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; - fn encode_metadata(&self, - tcx: &ty::ctxt<'tcx>, - reexports: &def::ExportMap, - item_symbols: &RefCell>, - link_meta: &LinkMeta, - reachable: &NodeSet, - krate: &hir::Crate) -> Vec; - fn metadata_encoding_version(&self) -> &[u8]; -} - -impl<'tcx> CrateStore<'tcx> for cstore::CStore { - fn stability(&self, def: DefId) -> Option - { - let cdata = self.get_crate_data(def.krate); - decoder::get_stability(&*cdata, def.index) - } - - fn closure_kind(&self, _tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind - { - assert!(!def_id.is_local()); - let cdata = self.get_crate_data(def_id.krate); - decoder::closure_kind(&*cdata, def_id.index) - } - - fn closure_ty(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> - { - assert!(!def_id.is_local()); - let cdata = self.get_crate_data(def_id.krate); - decoder::closure_ty(&*cdata, def_id.index, tcx) - } - - fn item_variances(&self, def: DefId) -> ty::ItemVariances { - let cdata = self.get_crate_data(def.krate); - decoder::get_item_variances(&*cdata, def.index) - } - - fn repr_attrs(&self, def: DefId) -> Vec { - let cdata = self.get_crate_data(def.krate); - decoder::get_repr_attrs(&*cdata, def.index) - } - - fn item_type(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::TypeScheme<'tcx> - { - let cdata = self.get_crate_data(def.krate); - decoder::get_type(&*cdata, def.index, tcx) - } - - fn item_predicates(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::GenericPredicates<'tcx> - { - let cdata = self.get_crate_data(def.krate); - decoder::get_predicates(&*cdata, def.index, tcx) - } - - fn item_super_predicates(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::GenericPredicates<'tcx> - { - let cdata = self.get_crate_data(def.krate); - decoder::get_super_predicates(&*cdata, def.index, tcx) - } - - fn item_attrs(&self, def_id: DefId) -> Vec - { - let cdata = self.get_crate_data(def_id.krate); - decoder::get_item_attrs(&*cdata, def_id.index) - } - - fn item_symbol(&self, def: DefId) -> String - { - let cdata = self.get_crate_data(def.krate); - decoder::get_symbol(&cdata, def.index) - } - - fn trait_def(&self, tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::TraitDef<'tcx> - { - let cdata = self.get_crate_data(def.krate); - decoder::get_trait_def(&*cdata, def.index, tcx) - } - - fn adt_def(&self, tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> - { - let cdata = self.get_crate_data(def.krate); - decoder::get_adt_def(&self.intr, &*cdata, def.index, tcx) - } - - fn method_arg_names(&self, did: DefId) -> Vec - { - let cdata = self.get_crate_data(did.krate); - decoder::get_method_arg_names(&cdata, did.index) - } - - fn item_path(&self, def: DefId) -> Vec { - let cdata = self.get_crate_data(def.krate); - let path = decoder::get_item_path(&*cdata, def.index); - - cdata.with_local_path(|cpath| { - let mut r = Vec::with_capacity(cpath.len() + path.len()); - r.push_all(cpath); - r.push_all(&path); - r - }) - } - - fn item_name(&self, def: DefId) -> ast::Name { - let cdata = self.get_crate_data(def.krate); - decoder::get_item_name(&self.intr, &cdata, def.index) - } - - - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec - { - let mut result = vec![]; - let cdata = self.get_crate_data(def_id.krate); - decoder::each_inherent_implementation_for_type(&*cdata, def_id.index, - |iid| result.push(iid)); - result - } - - fn implementations_of_trait(&self, def_id: DefId) -> Vec - { - let mut result = vec![]; - self.iter_crate_data(|_, cdata| { - decoder::each_implementation_for_trait(cdata, def_id, &mut |iid| { - result.push(iid) - }) - }); - result - } - - fn provided_trait_methods(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> Vec>> - { - let cdata = self.get_crate_data(def.krate); - decoder::get_provided_trait_methods(self.intr.clone(), &*cdata, def.index, tcx) - } - - fn trait_item_def_ids(&self, def: DefId) - -> Vec - { - let cdata = self.get_crate_data(def.krate); - decoder::get_trait_item_def_ids(&*cdata, def.index) - } - - fn impl_items(&self, impl_def_id: DefId) -> Vec - { - let cdata = self.get_crate_data(impl_def_id.krate); - decoder::get_impl_items(&*cdata, impl_def_id.index) - } - - fn impl_polarity(&self, def: DefId) -> Option - { - let cdata = self.get_crate_data(def.krate); - decoder::get_impl_polarity(&*cdata, def.index) - } - - fn impl_trait_ref(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> Option> - { - let cdata = self.get_crate_data(def.krate); - decoder::get_impl_trait(&*cdata, def.index, tcx) - } - - fn custom_coerce_unsized_kind(&self, def: DefId) - -> Option - { - let cdata = self.get_crate_data(def.krate); - decoder::get_custom_coerce_unsized_kind(&*cdata, def.index) - } - - // FIXME: killme - fn associated_consts(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> Vec>> { - let cdata = self.get_crate_data(def.krate); - decoder::get_associated_consts(self.intr.clone(), &*cdata, def.index, tcx) - } - - fn trait_of_item(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) -> Option - { - let cdata = self.get_crate_data(def_id.krate); - decoder::get_trait_of_item(&*cdata, def_id.index, tcx) - } - - fn impl_or_trait_item(&self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> ty::ImplOrTraitItem<'tcx> - { - let cdata = self.get_crate_data(def.krate); - decoder::get_impl_or_trait_item( - self.intr.clone(), - &*cdata, - def.index, - tcx) - } - - fn is_const_fn(&self, did: DefId) -> bool - { - let cdata = self.get_crate_data(did.krate); - decoder::is_const_fn(&cdata, did.index) - } - - fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool - { - let cdata = self.get_crate_data(trait_def_id.krate); - decoder::is_defaulted_trait(&*cdata, trait_def_id.index) - } - - fn is_impl(&self, did: DefId) -> bool - { - let cdata = self.get_crate_data(did.krate); - decoder::is_impl(&*cdata, did.index) - } - - fn is_default_impl(&self, impl_did: DefId) -> bool { - let cdata = self.get_crate_data(impl_did.krate); - decoder::is_default_impl(&*cdata, impl_did.index) - } - - fn is_extern_fn(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool - { - let cdata = self.get_crate_data(did.krate); - decoder::is_extern_fn(&*cdata, did.index, tcx) - } - - fn is_static(&self, did: DefId) -> bool - { - let cdata = self.get_crate_data(did.krate); - decoder::is_static(&*cdata, did.index) - } - - fn is_static_method(&self, def: DefId) -> bool - { - let cdata = self.get_crate_data(def.krate); - decoder::is_static_method(&*cdata, def.index) - } - - fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool - { - self.do_is_statically_included_foreign_item(id) - } - - fn is_typedef(&self, did: DefId) -> bool { - let cdata = self.get_crate_data(did.krate); - decoder::is_typedef(&*cdata, did.index) - } - - fn dylib_dependency_formats(&self, cnum: ast::CrateNum) - -> Vec<(ast::CrateNum, LinkagePreference)> - { - let cdata = self.get_crate_data(cnum); - decoder::get_dylib_dependency_formats(&cdata) - } - - fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)> - { - let mut result = vec![]; - let crate_data = self.get_crate_data(cnum); - decoder::each_lang_item(&*crate_data, |did, lid| { - result.push((did, lid)); true - }); - result - } - - fn missing_lang_items(&self, cnum: ast::CrateNum) - -> Vec - { - let cdata = self.get_crate_data(cnum); - decoder::get_missing_lang_items(&*cdata) - } - - fn is_staged_api(&self, cnum: ast::CrateNum) -> bool - { - self.get_crate_data(cnum).staged_api - } - - fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool - { - self.get_crate_data(cnum).explicitly_linked.get() - } - - fn is_allocator(&self, cnum: ast::CrateNum) -> bool - { - self.get_crate_data(cnum).is_allocator() - } - - fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec - { - decoder::get_crate_attributes(self.get_crate_data(cnum).data()) - } - - fn crate_name(&self, cnum: ast::CrateNum) -> String - { - self.get_crate_data(cnum).name.clone() - } - - fn crate_hash(&self, cnum: ast::CrateNum) -> Svh - { - let cdata = self.get_crate_data(cnum); - decoder::get_crate_hash(cdata.data()) - } - - fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) - -> FnvHashMap> - { - decoder::get_struct_field_attrs(&*self.get_crate_data(cnum)) - } - - fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option - { - let cdata = self.get_crate_data(cnum); - decoder::get_plugin_registrar_fn(cdata.data()).map(|index| DefId { - krate: cnum, - index: index - }) - } - - fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)> - { - let cdata = self.get_crate_data(cnum); - decoder::get_native_libraries(&*cdata) - } - - fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec - { - let cdata = self.get_crate_data(cnum); - decoder::get_reachable_ids(&*cdata) - } - - fn def_path(&self, def: DefId) -> ast_map::DefPath - { - let cdata = self.get_crate_data(def.krate); - let path = decoder::def_path(&*cdata, def.index); - let local_path = cdata.local_def_path(); - local_path.into_iter().chain(path).collect() - } - - fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option - { - let cdata = self.get_crate_data(did.krate); - decoder::get_tuple_struct_definition_if_ctor(&*cdata, did.index) - } - - fn struct_field_names(&self, def: DefId) -> Vec - { - let cdata = self.get_crate_data(def.krate); - decoder::get_struct_field_names(&self.intr, &*cdata, def.index) - } - - fn item_children(&self, def_id: DefId) -> Vec - { - let mut result = vec![]; - let crate_data = self.get_crate_data(def_id.krate); - let get_crate_data = |cnum| self.get_crate_data(cnum); - decoder::each_child_of_item( - self.intr.clone(), &*crate_data, - def_id.index, get_crate_data, - |def, name, vis| result.push(ChildItem { - def: def, - name: name, - vis: vis - })); - result - } - - fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec - { - let mut result = vec![]; - let crate_data = self.get_crate_data(cnum); - let get_crate_data = |cnum| self.get_crate_data(cnum); - decoder::each_top_level_item_of_crate( - self.intr.clone(), &*crate_data, get_crate_data, - |def, name, vis| result.push(ChildItem { - def: def, - name: name, - vis: vis - })); - result - } - - fn maybe_get_item_ast(&'tcx self, tcx: &ty::ctxt<'tcx>, def: DefId) - -> FoundAst<'tcx> - { - let cdata = self.get_crate_data(def.krate); - let decode_inlined_item = Box::new(astencode::decode_inlined_item); - decoder::maybe_get_item_ast(&*cdata, tcx, def.index, decode_inlined_item) - } - - fn crates(&self) -> Vec - { - let mut result = vec![]; - self.iter_crate_data(|cnum, _| result.push(cnum)); - result - } - - fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> - { - self.get_used_libraries().borrow().clone() - } - - fn used_link_args(&self) -> Vec - { - self.get_used_link_args().borrow().clone() - } - - fn metadata_filename(&self) -> &str - { - loader::METADATA_FILENAME - } - - fn metadata_section_name(&self, target: &Target) -> &str - { - loader::meta_section_name(target) - } - fn encode_type(&self, tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Vec - { - encoder::encoded_ty(tcx, ty) - } - - fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)> - { - self.do_get_used_crates(prefer) - } - - fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource - { - self.do_get_used_crate_source(cnum).unwrap() - } - - fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option - { - self.find_extern_mod_stmt_cnum(emod_id) - } - - fn encode_metadata(&self, - tcx: &ty::ctxt<'tcx>, - reexports: &def::ExportMap, - item_symbols: &RefCell>, - link_meta: &LinkMeta, - reachable: &NodeSet, - krate: &hir::Crate) -> Vec - { - let encode_inlined_item: encoder::EncodeInlinedItem = - Box::new(|ecx, rbml_w, ii| astencode::encode_inlined_item(ecx, rbml_w, ii)); - - let encode_params = encoder::EncodeParams { - diag: tcx.sess.diagnostic(), - tcx: tcx, - reexports: reexports, - item_symbols: item_symbols, - link_meta: link_meta, - cstore: self, - encode_inlined_item: encode_inlined_item, - reachable: reachable - }; - encoder::encode_metadata(encode_params, krate) - - } - - fn metadata_encoding_version(&self) -> &[u8] - { - encoder::metadata_encoding_version - } -} diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs deleted file mode 100644 index 752fdc23474..00000000000 --- a/src/librustc/middle/astencode.rs +++ /dev/null @@ -1,1464 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_camel_case_types)] -// FIXME: remove this after snapshot, and Results are handled -#![allow(unused_must_use)] - -use front::map as ast_map; -use rustc_front::hir; -use rustc_front::fold; -use rustc_front::fold::Folder; - -use metadata::common as c; -use metadata::cstore as cstore; -use session::Session; -use metadata::decoder; -use metadata::encoder as e; -use metadata::inline::{InlinedItem, InlinedItemRef}; -use metadata::tydecode; -use metadata::tyencode; -use middle::ty::adjustment; -use middle::ty::cast; -use middle::check_const::ConstQualif; -use middle::def; -use middle::def_id::DefId; -use middle::privacy::{AllPublic, LastMod}; -use middle::region; -use middle::subst; -use middle::ty::{self, Ty}; - -use syntax::{ast, ast_util, codemap}; -use syntax::ast::NodeIdAssigner; -use syntax::codemap::Span; -use syntax::ptr::P; - -use std::cell::Cell; -use std::io::SeekFrom; -use std::io::prelude::*; -use std::fmt::Debug; - -use rbml::reader; -use rbml::writer::Encoder; -use rbml; -use serialize; -use serialize::{Decodable, Decoder, DecoderHelpers, Encodable}; -use serialize::EncoderHelpers; - -#[cfg(test)] use std::io::Cursor; -#[cfg(test)] use syntax::parse; -#[cfg(test)] use syntax::ast::NodeId; -#[cfg(test)] use rustc_front::print::pprust; -#[cfg(test)] use rustc_front::lowering::{lower_item, LoweringContext}; - -struct DecodeContext<'a, 'b, 'tcx: 'a> { - tcx: &'a ty::ctxt<'tcx>, - cdata: &'b cstore::crate_metadata, - from_id_range: ast_util::IdRange, - to_id_range: ast_util::IdRange, - // Cache the last used filemap for translating spans as an optimization. - last_filemap_index: Cell, -} - -trait tr { - fn tr(&self, dcx: &DecodeContext) -> Self; -} - -// ______________________________________________________________________ -// Top-level methods. - -pub fn encode_inlined_item(ecx: &e::EncodeContext, - rbml_w: &mut Encoder, - ii: InlinedItemRef) { - let id = match ii { - InlinedItemRef::Item(i) => i.id, - InlinedItemRef::Foreign(i) => i.id, - InlinedItemRef::TraitItem(_, ti) => ti.id, - InlinedItemRef::ImplItem(_, ii) => ii.id, - }; - debug!("> Encoding inlined item: {} ({:?})", - ecx.tcx.map.path_to_string(id), - rbml_w.writer.seek(SeekFrom::Current(0))); - - // Folding could be avoided with a smarter encoder. - let ii = simplify_ast(ii); - let id_range = ii.compute_id_range(); - - rbml_w.start_tag(c::tag_ast as usize); - id_range.encode(rbml_w); - encode_ast(rbml_w, &ii); - encode_side_tables_for_ii(ecx, rbml_w, &ii); - rbml_w.end_tag(); - - debug!("< Encoded inlined fn: {} ({:?})", - ecx.tcx.map.path_to_string(id), - rbml_w.writer.seek(SeekFrom::Current(0))); -} - -impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> { - fn new_id(&self, id: ast::NodeId) -> ast::NodeId { - if id == ast::DUMMY_NODE_ID { - // Used by ast_map to map the NodeInlinedParent. - self.tcx.sess.next_node_id() - } else { - self.tr_id(id) - } - } - fn new_def_id(&self, def_id: DefId) -> DefId { - self.tr_def_id(def_id) - } - fn new_span(&self, span: Span) -> Span { - self.tr_span(span) - } -} - -/// Decodes an item from its AST in the cdata's metadata and adds it to the -/// ast-map. -pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, - tcx: &ty::ctxt<'tcx>, - path: Vec, - def_path: ast_map::DefPath, - par_doc: rbml::Doc, - orig_did: DefId) - -> Result<&'tcx InlinedItem, (Vec, - ast_map::DefPath)> { - match par_doc.opt_child(c::tag_ast) { - None => Err((path, def_path)), - Some(ast_doc) => { - let mut path_as_str = None; - debug!("> Decoding inlined fn: {:?}::?", - { - // Do an Option dance to use the path after it is moved below. - let s = ast_map::path_to_string(path.iter().cloned()); - path_as_str = Some(s); - path_as_str.as_ref().map(|x| &x[..]) - }); - let mut ast_dsr = reader::Decoder::new(ast_doc); - let from_id_range = Decodable::decode(&mut ast_dsr).unwrap(); - let to_id_range = reserve_id_range(&tcx.sess, from_id_range); - let dcx = &DecodeContext { - cdata: cdata, - tcx: tcx, - from_id_range: from_id_range, - to_id_range: to_id_range, - last_filemap_index: Cell::new(0) - }; - let raw_ii = decode_ast(ast_doc); - let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, def_path, raw_ii, dcx); - - let name = match *ii { - InlinedItem::Item(ref i) => i.name, - InlinedItem::Foreign(ref i) => i.name, - InlinedItem::TraitItem(_, ref ti) => ti.name, - InlinedItem::ImplItem(_, ref ii) => ii.name - }; - debug!("Fn named: {}", name); - debug!("< Decoded inlined fn: {}::{}", - path_as_str.unwrap(), - name); - region::resolve_inlined_item(&tcx.sess, &tcx.region_maps, ii); - decode_side_tables(dcx, ast_doc); - copy_item_types(dcx, ii, orig_did); - match *ii { - InlinedItem::Item(ref i) => { - debug!(">>> DECODED ITEM >>>\n{}\n<<< DECODED ITEM <<<", - ::rustc_front::print::pprust::item_to_string(&**i)); - } - _ => { } - } - Ok(ii) - } - } -} - -// ______________________________________________________________________ -// Enumerating the IDs which appear in an AST - -fn reserve_id_range(sess: &Session, - from_id_range: ast_util::IdRange) -> ast_util::IdRange { - // Handle the case of an empty range: - if from_id_range.empty() { return from_id_range; } - let cnt = from_id_range.max - from_id_range.min; - let to_id_min = sess.reserve_node_ids(cnt); - let to_id_max = to_id_min + cnt; - ast_util::IdRange { min: to_id_min, max: to_id_max } -} - -impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> { - /// Translates an internal id, meaning a node id that is known to refer to some part of the - /// item currently being inlined, such as a local variable or argument. All naked node-ids - /// that appear in types have this property, since if something might refer to an external item - /// we would use a def-id to allow for the possibility that the item resides in another crate. - pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId { - // from_id_range should be non-empty - assert!(!self.from_id_range.empty()); - // Use wrapping arithmetic because otherwise it introduces control flow. - // Maybe we should just have the control flow? -- aatch - (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min)) - } - - /// Translates an EXTERNAL def-id, converting the crate number from the one used in the encoded - /// data to the current crate numbers.. By external, I mean that it be translated to a - /// reference to the item in its original crate, as opposed to being translated to a reference - /// to the inlined version of the item. This is typically, but not always, what you want, - /// because most def-ids refer to external things like types or other fns that may or may not - /// be inlined. Note that even when the inlined function is referencing itself recursively, we - /// would want `tr_def_id` for that reference--- conceptually the function calls the original, - /// non-inlined version, and trans deals with linking that recursive call to the inlined copy. - pub fn tr_def_id(&self, did: DefId) -> DefId { - decoder::translate_def_id(self.cdata, did) - } - - /// Translates a `Span` from an extern crate to the corresponding `Span` - /// within the local crate's codemap. `creader::import_codemap()` will - /// already have allocated any additionally needed FileMaps in the local - /// codemap as a side-effect of creating the crate_metadata's - /// `codemap_import_info`. - pub fn tr_span(&self, span: Span) -> Span { - let span = if span.lo > span.hi { - // Currently macro expansion sometimes produces invalid Span values - // where lo > hi. In order not to crash the compiler when trying to - // translate these values, let's transform them into something we - // can handle (and which will produce useful debug locations at - // least some of the time). - // This workaround is only necessary as long as macro expansion is - // not fixed. FIXME(#23480) - codemap::mk_sp(span.lo, span.lo) - } else { - span - }; - - let imported_filemaps = self.cdata.imported_filemaps(self.tcx.sess.codemap()); - let filemap = { - // Optimize for the case that most spans within a translated item - // originate from the same filemap. - let last_filemap_index = self.last_filemap_index.get(); - let last_filemap = &imported_filemaps[last_filemap_index]; - - if span.lo >= last_filemap.original_start_pos && - span.lo <= last_filemap.original_end_pos && - span.hi >= last_filemap.original_start_pos && - span.hi <= last_filemap.original_end_pos { - last_filemap - } else { - let mut a = 0; - let mut b = imported_filemaps.len(); - - while b - a > 1 { - let m = (a + b) / 2; - if imported_filemaps[m].original_start_pos > span.lo { - b = m; - } else { - a = m; - } - } - - self.last_filemap_index.set(a); - &imported_filemaps[a] - } - }; - - let lo = (span.lo - filemap.original_start_pos) + - filemap.translated_filemap.start_pos; - let hi = (span.hi - filemap.original_start_pos) + - filemap.translated_filemap.start_pos; - - codemap::mk_sp(lo, hi) - } -} - -impl tr for DefId { - fn tr(&self, dcx: &DecodeContext) -> DefId { - dcx.tr_def_id(*self) - } -} - -impl tr for Option { - fn tr(&self, dcx: &DecodeContext) -> Option { - self.map(|d| dcx.tr_def_id(d)) - } -} - -impl tr for Span { - fn tr(&self, dcx: &DecodeContext) -> Span { - dcx.tr_span(*self) - } -} - -trait def_id_encoder_helpers { - fn emit_def_id(&mut self, did: DefId); -} - -impl def_id_encoder_helpers for S - where ::Error: Debug -{ - fn emit_def_id(&mut self, did: DefId) { - did.encode(self).unwrap() - } -} - -trait def_id_decoder_helpers { - fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId; - fn read_def_id_nodcx(&mut self, - cdata: &cstore::crate_metadata) -> DefId; -} - -impl def_id_decoder_helpers for D - where ::Error: Debug -{ - fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId { - let did: DefId = Decodable::decode(self).unwrap(); - did.tr(dcx) - } - - fn read_def_id_nodcx(&mut self, - cdata: &cstore::crate_metadata) - -> DefId { - let did: DefId = Decodable::decode(self).unwrap(); - decoder::translate_def_id(cdata, did) - } -} - -// ______________________________________________________________________ -// Encoding and decoding the AST itself -// -// When decoding, we have to renumber the AST so that the node ids that -// appear within are disjoint from the node ids in our existing ASTs. -// We also have to adjust the spans: for now we just insert a dummy span, -// but eventually we should add entries to the local codemap as required. - -fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) { - rbml_w.start_tag(c::tag_tree as usize); - item.encode(rbml_w); - rbml_w.end_tag(); -} - -struct NestedItemsDropper; - -impl Folder for NestedItemsDropper { - fn fold_block(&mut self, blk: P) -> P { - blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| { - let stmts_sans_items = stmts.into_iter().filter_map(|stmt| { - let use_stmt = match stmt.node { - hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true, - hir::StmtDecl(ref decl, _) => { - match decl.node { - hir::DeclLocal(_) => true, - hir::DeclItem(_) => false, - } - } - }; - if use_stmt { - Some(stmt) - } else { - None - } - }).collect(); - let blk_sans_items = P(hir::Block { - stmts: stmts_sans_items, - expr: expr, - id: id, - rules: rules, - span: span, - }); - fold::noop_fold_block(blk_sans_items, self) - }) - } -} - -// Produces a simplified copy of the AST which does not include things -// that we do not need to or do not want to export. For example, we -// do not include any nested items: if these nested items are to be -// inlined, their AST will be exported separately (this only makes -// sense because, in Rust, nested items are independent except for -// their visibility). -// -// As it happens, trans relies on the fact that we do not export -// nested items, as otherwise it would get confused when translating -// inlined items. -fn simplify_ast(ii: InlinedItemRef) -> InlinedItem { - let mut fld = NestedItemsDropper; - - match ii { - // HACK we're not dropping items. - InlinedItemRef::Item(i) => { - InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld))) - } - InlinedItemRef::TraitItem(d, ti) => { - InlinedItem::TraitItem(d, fold::noop_fold_trait_item(P(ti.clone()), &mut fld)) - } - InlinedItemRef::ImplItem(d, ii) => { - InlinedItem::ImplItem(d, fold::noop_fold_impl_item(P(ii.clone()), &mut fld)) - } - InlinedItemRef::Foreign(i) => { - InlinedItem::Foreign(fold::noop_fold_foreign_item(P(i.clone()), &mut fld)) - } - } -} - -fn decode_ast(par_doc: rbml::Doc) -> InlinedItem { - let chi_doc = par_doc.get(c::tag_tree as usize); - let mut d = reader::Decoder::new(chi_doc); - Decodable::decode(&mut d).unwrap() -} - -// ______________________________________________________________________ -// Encoding and decoding of ast::def - -fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> def::Def { - let def: def::Def = Decodable::decode(dsr).unwrap(); - def.tr(dcx) -} - -impl tr for def::Def { - fn tr(&self, dcx: &DecodeContext) -> def::Def { - match *self { - def::DefFn(did, is_ctor) => def::DefFn(did.tr(dcx), is_ctor), - def::DefMethod(did) => def::DefMethod(did.tr(dcx)), - def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)), - impl_ids.map(|(nid1, nid2)| { - (dcx.tr_id(nid1), - dcx.tr_id(nid2)) - })) } - def::DefMod(did) => { def::DefMod(did.tr(dcx)) } - def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) } - def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) } - def::DefConst(did) => { def::DefConst(did.tr(dcx)) } - def::DefAssociatedConst(did) => def::DefAssociatedConst(did.tr(dcx)), - def::DefLocal(_, nid) => { - let nid = dcx.tr_id(nid); - let did = dcx.tcx.map.local_def_id(nid); - def::DefLocal(did, nid) - } - def::DefVariant(e_did, v_did, is_s) => { - def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s) - }, - def::DefTrait(did) => def::DefTrait(did.tr(dcx)), - def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum), - def::DefAssociatedTy(trait_did, did) => - def::DefAssociatedTy(trait_did.tr(dcx), did.tr(dcx)), - def::DefPrimTy(p) => def::DefPrimTy(p), - def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n), - def::DefUse(did) => def::DefUse(did.tr(dcx)), - def::DefUpvar(_, nid1, index, nid2) => { - let nid1 = dcx.tr_id(nid1); - let nid2 = dcx.tr_id(nid2); - let did1 = dcx.tcx.map.local_def_id(nid1); - def::DefUpvar(did1, nid1, index, nid2) - } - def::DefStruct(did) => def::DefStruct(did.tr(dcx)), - def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid)) - } - } -} - -// ______________________________________________________________________ -// Encoding and decoding of freevar information - -fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &ty::Freevar) { - (*fv).encode(rbml_w).unwrap(); -} - -trait rbml_decoder_helper { - fn read_freevar_entry(&mut self, dcx: &DecodeContext) - -> ty::Freevar; - fn read_capture_mode(&mut self) -> hir::CaptureClause; -} - -impl<'a> rbml_decoder_helper for reader::Decoder<'a> { - fn read_freevar_entry(&mut self, dcx: &DecodeContext) - -> ty::Freevar { - let fv: ty::Freevar = Decodable::decode(self).unwrap(); - fv.tr(dcx) - } - - fn read_capture_mode(&mut self) -> hir::CaptureClause { - let cm: hir::CaptureClause = Decodable::decode(self).unwrap(); - cm - } -} - -impl tr for ty::Freevar { - fn tr(&self, dcx: &DecodeContext) -> ty::Freevar { - ty::Freevar { - def: self.def.tr(dcx), - span: self.span.tr(dcx), - } - } -} - -// ______________________________________________________________________ -// Encoding and decoding of MethodCallee - -trait read_method_callee_helper<'tcx> { - fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> (u32, ty::MethodCallee<'tcx>); -} - -fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - autoderef: u32, - method: &ty::MethodCallee<'tcx>) { - use serialize::Encoder; - - rbml_w.emit_struct("MethodCallee", 4, |rbml_w| { - rbml_w.emit_struct_field("autoderef", 0, |rbml_w| { - autoderef.encode(rbml_w) - }); - rbml_w.emit_struct_field("def_id", 1, |rbml_w| { - Ok(rbml_w.emit_def_id(method.def_id)) - }); - rbml_w.emit_struct_field("ty", 2, |rbml_w| { - Ok(rbml_w.emit_ty(ecx, method.ty)) - }); - rbml_w.emit_struct_field("substs", 3, |rbml_w| { - Ok(rbml_w.emit_substs(ecx, &method.substs)) - }) - }).unwrap(); -} - -impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { - fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> (u32, ty::MethodCallee<'tcx>) { - - self.read_struct("MethodCallee", 4, |this| { - let autoderef = this.read_struct_field("autoderef", 0, - Decodable::decode).unwrap(); - Ok((autoderef, ty::MethodCallee { - def_id: this.read_struct_field("def_id", 1, |this| { - Ok(this.read_def_id(dcx)) - }).unwrap(), - ty: this.read_struct_field("ty", 2, |this| { - Ok(this.read_ty(dcx)) - }).unwrap(), - substs: this.read_struct_field("substs", 3, |this| { - Ok(dcx.tcx.mk_substs(this.read_substs(dcx))) - }).unwrap() - })) - }).unwrap() - } -} - -pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) { - kind.encode(ebml_w).unwrap(); -} - -// ______________________________________________________________________ -// Encoding and decoding the side tables - -trait get_ty_str_ctxt<'tcx> { - fn ty_str_ctxt<'a>(&'a self) -> tyencode::ctxt<'a, 'tcx>; -} - -impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> { - fn ty_str_ctxt<'b>(&'b self) -> tyencode::ctxt<'b, 'tcx> { - tyencode::ctxt { - diag: self.tcx.sess.diagnostic(), - ds: e::def_to_string, - tcx: self.tcx, - abbrevs: &self.type_abbrevs - } - } -} - -trait rbml_writer_helpers<'tcx> { - fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region); - fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); - fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]); - fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - predicate: &ty::Predicate<'tcx>); - fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - ty: &ty::TraitRef<'tcx>); - fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - substs: &subst::Substs<'tcx>); - fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, - bounds: &ty::ExistentialBounds<'tcx>); - fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); - fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture); - fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - adj: &adjustment::AutoAdjustment<'tcx>); - fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - autoref: &adjustment::AutoRef<'tcx>); - fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - auto_deref_ref: &adjustment::AutoDerefRef<'tcx>); -} - -impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { - fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) { - self.emit_opaque(|this| Ok(e::write_region(ecx, this, r))); - } - - fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) { - self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty))); - } - - fn emit_tys<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, tys: &[Ty<'tcx>]) { - self.emit_from_vec(tys, |this, ty| Ok(this.emit_ty(ecx, *ty))); - } - - fn emit_trait_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - trait_ref: &ty::TraitRef<'tcx>) { - self.emit_opaque(|this| Ok(e::write_trait_ref(ecx, this, trait_ref))); - } - - fn emit_predicate<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - predicate: &ty::Predicate<'tcx>) { - self.emit_opaque(|this| { - Ok(tyencode::enc_predicate(this, - &ecx.ty_str_ctxt(), - predicate)) - }); - } - - fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, - bounds: &ty::ExistentialBounds<'tcx>) { - self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this, - &ecx.ty_str_ctxt(), - bounds))); - } - - fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds) { - self.emit_opaque(|this| Ok(tyencode::enc_builtin_bounds(this, - &ecx.ty_str_ctxt(), - bounds))); - } - - fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture) { - use serialize::Encoder; - - self.emit_enum("UpvarCapture", |this| { - match *capture { - ty::UpvarCapture::ByValue => { - this.emit_enum_variant("ByValue", 1, 0, |_| Ok(())) - } - ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, region }) => { - this.emit_enum_variant("ByRef", 2, 0, |this| { - this.emit_enum_variant_arg(0, - |this| kind.encode(this)); - this.emit_enum_variant_arg(1, - |this| Ok(this.emit_region(ecx, region))) - }) - } - } - }).unwrap() - } - - fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - substs: &subst::Substs<'tcx>) { - self.emit_opaque(|this| Ok(tyencode::enc_substs(this, - &ecx.ty_str_ctxt(), - substs))); - } - - fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - adj: &adjustment::AutoAdjustment<'tcx>) { - use serialize::Encoder; - - self.emit_enum("AutoAdjustment", |this| { - match *adj { - adjustment::AdjustReifyFnPointer=> { - this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(())) - } - - adjustment::AdjustUnsafeFnPointer => { - this.emit_enum_variant("AdjustUnsafeFnPointer", 2, 0, |_| { - Ok(()) - }) - } - - adjustment::AdjustDerefRef(ref auto_deref_ref) => { - this.emit_enum_variant("AdjustDerefRef", 3, 2, |this| { - this.emit_enum_variant_arg(0, - |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) - }) - } - } - }); - } - - fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - autoref: &adjustment::AutoRef<'tcx>) { - use serialize::Encoder; - - self.emit_enum("AutoRef", |this| { - match autoref { - &adjustment::AutoPtr(r, m) => { - this.emit_enum_variant("AutoPtr", 0, 2, |this| { - this.emit_enum_variant_arg(0, - |this| Ok(this.emit_region(ecx, *r))); - this.emit_enum_variant_arg(1, |this| m.encode(this)) - }) - } - &adjustment::AutoUnsafe(m) => { - this.emit_enum_variant("AutoUnsafe", 1, 1, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)) - }) - } - } - }); - } - - fn emit_auto_deref_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - auto_deref_ref: &adjustment::AutoDerefRef<'tcx>) { - use serialize::Encoder; - - self.emit_struct("AutoDerefRef", 2, |this| { - this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); - - this.emit_struct_field("autoref", 1, |this| { - this.emit_option(|this| { - match auto_deref_ref.autoref { - None => this.emit_option_none(), - Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), - } - }) - }); - - this.emit_struct_field("unsize", 2, |this| { - this.emit_option(|this| { - match auto_deref_ref.unsize { - None => this.emit_option_none(), - Some(target) => this.emit_option_some(|this| { - Ok(this.emit_ty(ecx, target)) - }) - } - }) - }) - }); - } -} - -trait write_tag_and_id { - fn tag(&mut self, tag_id: c::astencode_tag, f: F) where F: FnOnce(&mut Self); - fn id(&mut self, id: ast::NodeId); -} - -impl<'a> write_tag_and_id for Encoder<'a> { - fn tag(&mut self, - tag_id: c::astencode_tag, - f: F) where - F: FnOnce(&mut Encoder<'a>), - { - self.start_tag(tag_id as usize); - f(self); - self.end_tag(); - } - - fn id(&mut self, id: ast::NodeId) { - id.encode(self).unwrap(); - } -} - -struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { - ecx: &'a e::EncodeContext<'c, 'tcx>, - rbml_w: &'a mut Encoder<'b>, -} - -impl<'a, 'b, 'c, 'tcx> ast_util::IdVisitingOperation for - SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> { - fn visit_id(&mut self, id: ast::NodeId) { - encode_side_tables_for_id(self.ecx, self.rbml_w, id) - } -} - -fn encode_side_tables_for_ii(ecx: &e::EncodeContext, - rbml_w: &mut Encoder, - ii: &InlinedItem) { - rbml_w.start_tag(c::tag_table as usize); - ii.visit_ids(&mut SideTableEncodingIdVisitor { - ecx: ecx, - rbml_w: rbml_w - }); - rbml_w.end_tag(); -} - -fn encode_side_tables_for_id(ecx: &e::EncodeContext, - rbml_w: &mut Encoder, - id: ast::NodeId) { - let tcx = ecx.tcx; - - debug!("Encoding side tables for id {}", id); - - if let Some(def) = tcx.def_map.borrow().get(&id).map(|d| d.full_def()) { - rbml_w.tag(c::tag_table_def, |rbml_w| { - rbml_w.id(id); - def.encode(rbml_w).unwrap(); - }) - } - - if let Some(ty) = tcx.node_types().get(&id) { - rbml_w.tag(c::tag_table_node_type, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_ty(ecx, *ty); - }) - } - - if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) { - rbml_w.tag(c::tag_table_item_subst, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_substs(ecx, &item_substs.substs); - }) - } - - if let Some(fv) = tcx.freevars.borrow().get(&id) { - rbml_w.tag(c::tag_table_freevars, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_from_vec(fv, |rbml_w, fv_entry| { - Ok(encode_freevar_entry(rbml_w, fv_entry)) - }); - }); - - for freevar in fv { - rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| { - rbml_w.id(id); - - let var_id = freevar.def.var_id(); - let upvar_id = ty::UpvarId { - var_id: var_id, - closure_expr_id: id - }; - let upvar_capture = tcx.tables - .borrow() - .upvar_capture_map - .get(&upvar_id) - .unwrap() - .clone(); - var_id.encode(rbml_w); - rbml_w.emit_upvar_capture(ecx, &upvar_capture); - }) - } - } - - let method_call = ty::MethodCall::expr(id); - if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { - rbml_w.tag(c::tag_table_method_map, |rbml_w| { - rbml_w.id(id); - encode_method_callee(ecx, rbml_w, method_call.autoderef, method) - }) - } - - if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) { - match *adjustment { - adjustment::AdjustDerefRef(ref adj) => { - for autoderef in 0..adj.autoderefs { - let method_call = ty::MethodCall::autoderef(id, autoderef as u32); - if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { - rbml_w.tag(c::tag_table_method_map, |rbml_w| { - rbml_w.id(id); - encode_method_callee(ecx, rbml_w, - method_call.autoderef, method) - }) - } - } - } - _ => {} - } - - rbml_w.tag(c::tag_table_adjustments, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_auto_adjustment(ecx, adjustment); - }) - } - - if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) { - rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| { - rbml_w.id(id); - encode_cast_kind(rbml_w, *cast_kind) - }) - } - - if let Some(qualif) = tcx.const_qualif_map.borrow().get(&id) { - rbml_w.tag(c::tag_table_const_qualif, |rbml_w| { - rbml_w.id(id); - qualif.encode(rbml_w).unwrap() - }) - } -} - -trait doc_decoder_helpers: Sized { - fn as_int(&self) -> isize; - fn opt_child(&self, tag: c::astencode_tag) -> Option; -} - -impl<'a> doc_decoder_helpers for rbml::Doc<'a> { - fn as_int(&self) -> isize { reader::doc_as_u64(*self) as isize } - fn opt_child(&self, tag: c::astencode_tag) -> Option> { - reader::maybe_get_doc(*self, tag as usize) - } -} - -trait rbml_decoder_decoder_helpers<'tcx> { - fn read_ty_encoded<'a, 'b, F, R>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>, - f: F) -> R - where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R; - - fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region; - fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>; - fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec>; - fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::TraitRef<'tcx>; - fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::PolyTraitRef<'tcx>; - fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::Predicate<'tcx>; - fn read_existential_bounds<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::ExistentialBounds<'tcx>; - fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> subst::Substs<'tcx>; - fn read_upvar_capture(&mut self, dcx: &DecodeContext) - -> ty::UpvarCapture; - fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> adjustment::AutoAdjustment<'tcx>; - fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> cast::CastKind; - fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> adjustment::AutoDerefRef<'tcx>; - fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> adjustment::AutoRef<'tcx>; - fn convert_def_id(&mut self, - dcx: &DecodeContext, - did: DefId) - -> DefId; - - // Versions of the type reading functions that don't need the full - // DecodeContext. - fn read_ty_nodcx(&mut self, - tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) -> Ty<'tcx>; - fn read_tys_nodcx(&mut self, - tcx: &ty::ctxt<'tcx>, - cdata: &cstore::crate_metadata) -> Vec>; - fn read_substs_nodcx(&mut self, tcx: &ty::ctxt<'tcx>, - cdata: &cstore::crate_metadata) - -> subst::Substs<'tcx>; -} - -impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { - fn read_ty_nodcx(&mut self, - tcx: &ty::ctxt<'tcx>, - cdata: &cstore::crate_metadata) - -> Ty<'tcx> { - self.read_opaque(|_, doc| { - Ok( - tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |id| decoder::translate_def_id(cdata, id)) - .parse_ty()) - }).unwrap() - } - - fn read_tys_nodcx(&mut self, - tcx: &ty::ctxt<'tcx>, - cdata: &cstore::crate_metadata) -> Vec> { - self.read_to_vec(|this| Ok(this.read_ty_nodcx(tcx, cdata)) ) - .unwrap() - .into_iter() - .collect() - } - - fn read_substs_nodcx(&mut self, - tcx: &ty::ctxt<'tcx>, - cdata: &cstore::crate_metadata) - -> subst::Substs<'tcx> - { - self.read_opaque(|_, doc| { - Ok( - tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |id| decoder::translate_def_id(cdata, id)) - .parse_substs()) - }).unwrap() - } - - fn read_ty_encoded<'b, 'c, F, R>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>, op: F) -> R - where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x,'tcx>) -> R - { - return self.read_opaque(|this, doc| { - debug!("read_ty_encoded({})", type_string(doc)); - Ok(op( - &mut tydecode::TyDecoder::with_doc( - dcx.tcx, dcx.cdata.cnum, doc, - &mut |a| this.convert_def_id(dcx, a)))) - }).unwrap(); - - fn type_string(doc: rbml::Doc) -> String { - let mut str = String::new(); - for i in doc.start..doc.end { - str.push(doc.data[i] as char); - } - str - } - } - fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region { - // Note: regions types embed local node ids. In principle, we - // should translate these node ids into the new decode - // context. However, we do not bother, because region types - // are not used during trans. This also applies to read_ty. - return self.read_ty_encoded(dcx, |decoder| decoder.parse_region()); - } - fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> { - return self.read_ty_encoded(dcx, |decoder| decoder.parse_ty()); - } - - fn read_tys<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> Vec> { - self.read_to_vec(|this| Ok(this.read_ty(dcx))).unwrap().into_iter().collect() - } - - fn read_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::TraitRef<'tcx> { - self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref()) - } - - fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::PolyTraitRef<'tcx> { - ty::Binder(self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref())) - } - - fn read_predicate<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::Predicate<'tcx> - { - self.read_ty_encoded(dcx, |decoder| decoder.parse_predicate()) - } - - fn read_existential_bounds<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::ExistentialBounds<'tcx> - { - self.read_ty_encoded(dcx, |decoder| decoder.parse_existential_bounds()) - } - - fn read_substs<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> subst::Substs<'tcx> { - self.read_opaque(|this, doc| { - Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc, - &mut |a| this.convert_def_id(dcx, a)) - .parse_substs()) - }).unwrap() - } - fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture { - self.read_enum("UpvarCapture", |this| { - let variants = ["ByValue", "ByRef"]; - this.read_enum_variant(&variants, |this, i| { - Ok(match i { - 1 => ty::UpvarCapture::ByValue, - 2 => ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: this.read_enum_variant_arg(0, - |this| Decodable::decode(this)).unwrap(), - region: this.read_enum_variant_arg(1, - |this| Ok(this.read_region(dcx))).unwrap() - }), - _ => panic!("bad enum variant for ty::UpvarCapture") - }) - }) - }).unwrap() - } - fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> adjustment::AutoAdjustment<'tcx> { - self.read_enum("AutoAdjustment", |this| { - let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"]; - this.read_enum_variant(&variants, |this, i| { - Ok(match i { - 1 => adjustment::AdjustReifyFnPointer, - 2 => adjustment::AdjustUnsafeFnPointer, - 3 => { - let auto_deref_ref: adjustment::AutoDerefRef = - this.read_enum_variant_arg(0, - |this| Ok(this.read_auto_deref_ref(dcx))).unwrap(); - - adjustment::AdjustDerefRef(auto_deref_ref) - } - _ => panic!("bad enum variant for adjustment::AutoAdjustment") - }) - }) - }).unwrap() - } - - fn read_auto_deref_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> adjustment::AutoDerefRef<'tcx> { - self.read_struct("AutoDerefRef", 2, |this| { - Ok(adjustment::AutoDerefRef { - autoderefs: this.read_struct_field("autoderefs", 0, |this| { - Decodable::decode(this) - }).unwrap(), - autoref: this.read_struct_field("autoref", 1, |this| { - this.read_option(|this, b| { - if b { - Ok(Some(this.read_autoref(dcx))) - } else { - Ok(None) - } - }) - }).unwrap(), - unsize: this.read_struct_field("unsize", 2, |this| { - this.read_option(|this, b| { - if b { - Ok(Some(this.read_ty(dcx))) - } else { - Ok(None) - } - }) - }).unwrap(), - }) - }).unwrap() - } - - fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> adjustment::AutoRef<'tcx> { - self.read_enum("AutoRef", |this| { - let variants = ["AutoPtr", "AutoUnsafe"]; - this.read_enum_variant(&variants, |this, i| { - Ok(match i { - 0 => { - let r: ty::Region = - this.read_enum_variant_arg(0, |this| { - Ok(this.read_region(dcx)) - }).unwrap(); - let m: hir::Mutability = - this.read_enum_variant_arg(1, |this| { - Decodable::decode(this) - }).unwrap(); - - adjustment::AutoPtr(dcx.tcx.mk_region(r), m) - } - 1 => { - let m: hir::Mutability = - this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - - adjustment::AutoUnsafe(m) - } - _ => panic!("bad enum variant for adjustment::AutoRef") - }) - }) - }).unwrap() - } - - fn read_cast_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>) - -> cast::CastKind - { - Decodable::decode(self).unwrap() - } - - /// Converts a def-id that appears in a type. The correct - /// translation will depend on what kind of def-id this is. - /// This is a subtle point: type definitions are not - /// inlined into the current crate, so if the def-id names - /// a nominal type or type alias, then it should be - /// translated to refer to the source crate. - /// - /// However, *type parameters* are cloned along with the function - /// they are attached to. So we should translate those def-ids - /// to refer to the new, cloned copy of the type parameter. - /// We only see references to free type parameters in the body of - /// an inlined function. In such cases, we need the def-id to - /// be a local id so that the TypeContents code is able to lookup - /// the relevant info in the ty_param_defs table. - /// - /// *Region parameters*, unfortunately, are another kettle of fish. - /// In such cases, def_id's can appear in types to distinguish - /// shadowed bound regions and so forth. It doesn't actually - /// matter so much what we do to these, since regions are erased - /// at trans time, but it's good to keep them consistent just in - /// case. We translate them with `tr_def_id()` which will map - /// the crate numbers back to the original source crate. - /// - /// Scopes will end up as being totally bogus. This can actually - /// be fixed though. - /// - /// Unboxed closures are cloned along with the function being - /// inlined, and all side tables use interned node IDs, so we - /// translate their def IDs accordingly. - /// - /// It'd be really nice to refactor the type repr to not include - /// def-ids so that all these distinctions were unnecessary. - fn convert_def_id(&mut self, - dcx: &DecodeContext, - did: DefId) - -> DefId { - let r = dcx.tr_def_id(did); - debug!("convert_def_id(did={:?})={:?}", did, r); - return r; - } -} - -fn decode_side_tables(dcx: &DecodeContext, - ast_doc: rbml::Doc) { - let tbl_doc = ast_doc.get(c::tag_table as usize); - for (tag, entry_doc) in reader::docs(tbl_doc) { - let mut entry_dsr = reader::Decoder::new(entry_doc); - let id0: ast::NodeId = Decodable::decode(&mut entry_dsr).unwrap(); - let id = dcx.tr_id(id0); - - debug!(">> Side table document with tag 0x{:x} \ - found for id {} (orig {})", - tag, id, id0); - let tag = tag as u32; - let decoded_tag: Option = c::astencode_tag::from_u32(tag); - match decoded_tag { - None => { - dcx.tcx.sess.bug( - &format!("unknown tag found in side tables: {:x}", - tag)); - } - Some(value) => { - let val_dsr = &mut entry_dsr; - - match value { - c::tag_table_def => { - let def = decode_def(dcx, val_dsr); - dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution { - base_def: def, - // This doesn't matter cross-crate. - last_private: LastMod(AllPublic), - depth: 0 - }); - } - c::tag_table_node_type => { - let ty = val_dsr.read_ty(dcx); - debug!("inserting ty for node {}: {:?}", - id, ty); - dcx.tcx.node_type_insert(id, ty); - } - c::tag_table_item_subst => { - let item_substs = ty::ItemSubsts { - substs: val_dsr.read_substs(dcx) - }; - dcx.tcx.tables.borrow_mut().item_substs.insert( - id, item_substs); - } - c::tag_table_freevars => { - let fv_info = val_dsr.read_to_vec(|val_dsr| { - Ok(val_dsr.read_freevar_entry(dcx)) - }).unwrap().into_iter().collect(); - dcx.tcx.freevars.borrow_mut().insert(id, fv_info); - } - c::tag_table_upvar_capture_map => { - let var_id: ast::NodeId = Decodable::decode(val_dsr).unwrap(); - let upvar_id = ty::UpvarId { - var_id: dcx.tr_id(var_id), - closure_expr_id: id - }; - let ub = val_dsr.read_upvar_capture(dcx); - dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); - } - c::tag_table_method_map => { - let (autoderef, method) = val_dsr.read_method_callee(dcx); - let method_call = ty::MethodCall { - expr_id: id, - autoderef: autoderef - }; - dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method); - } - c::tag_table_adjustments => { - let adj = - val_dsr.read_auto_adjustment(dcx); - dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); - } - c::tag_table_cast_kinds => { - let cast_kind = - val_dsr.read_cast_kind(dcx); - dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind); - } - c::tag_table_const_qualif => { - let qualif: ConstQualif = Decodable::decode(val_dsr).unwrap(); - dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif); - } - _ => { - dcx.tcx.sess.bug( - &format!("unknown tag found in side tables: {:x}", - tag)); - } - } - } - } - - debug!(">< Side table doc loaded"); - } -} - -// copy the tcache entries from the original item to the new -// inlined item -fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) { - fn copy_item_type(dcx: &DecodeContext, - inlined_id: ast::NodeId, - remote_did: DefId) { - let inlined_did = dcx.tcx.map.local_def_id(inlined_id); - dcx.tcx.register_item_type(inlined_did, - dcx.tcx.lookup_item_type(remote_did)); - - } - // copy the entry for the item itself - let item_node_id = match ii { - &InlinedItem::Item(ref i) => i.id, - &InlinedItem::TraitItem(_, ref ti) => ti.id, - &InlinedItem::ImplItem(_, ref ii) => ii.id, - &InlinedItem::Foreign(ref fi) => fi.id - }; - copy_item_type(dcx, item_node_id, orig_did); - - // copy the entries of inner items - if let &InlinedItem::Item(ref item) = ii { - match item.node { - hir::ItemEnum(ref def, _) => { - let orig_def = dcx.tcx.lookup_adt_def(orig_did); - for (i_variant, orig_variant) in - def.variants.iter().zip(orig_def.variants.iter()) - { - debug!("astencode: copying variant {:?} => {:?}", - orig_variant.did, i_variant.node.data.id()); - copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did); - } - } - hir::ItemStruct(ref def, _) => { - if !def.is_struct() { - let ctor_did = dcx.tcx.lookup_adt_def(orig_did) - .struct_variant().did; - debug!("astencode: copying ctor {:?} => {:?}", ctor_did, - def.id()); - copy_item_type(dcx, def.id(), ctor_did); - } - } - _ => {} - } - } -} - -// ______________________________________________________________________ -// Testing of astencode_gen - -#[cfg(test)] -fn encode_item_ast(rbml_w: &mut Encoder, item: &hir::Item) { - rbml_w.start_tag(c::tag_tree as usize); - (*item).encode(rbml_w); - rbml_w.end_tag(); -} - -#[cfg(test)] -fn decode_item_ast(par_doc: rbml::Doc) -> hir::Item { - let chi_doc = par_doc.get(c::tag_tree as usize); - let mut d = reader::Decoder::new(chi_doc); - Decodable::decode(&mut d).unwrap() -} - -#[cfg(test)] -trait FakeExtCtxt { - fn call_site(&self) -> codemap::Span; - fn cfg(&self) -> ast::CrateConfig; - fn ident_of(&self, st: &str) -> ast::Ident; - fn name_of(&self, st: &str) -> ast::Name; - fn parse_sess(&self) -> &parse::ParseSess; -} - -#[cfg(test)] -impl FakeExtCtxt for parse::ParseSess { - fn call_site(&self) -> codemap::Span { - codemap::Span { - lo: codemap::BytePos(0), - hi: codemap::BytePos(0), - expn_id: codemap::NO_EXPANSION, - } - } - fn cfg(&self) -> ast::CrateConfig { Vec::new() } - fn ident_of(&self, st: &str) -> ast::Ident { - parse::token::str_to_ident(st) - } - fn name_of(&self, st: &str) -> ast::Name { - parse::token::intern(st) - } - fn parse_sess(&self) -> &parse::ParseSess { self } -} - -#[cfg(test)] -struct FakeNodeIdAssigner; - -#[cfg(test)] -// It should go without saying that this may give unexpected results. Avoid -// lowering anything which needs new nodes. -impl NodeIdAssigner for FakeNodeIdAssigner { - fn next_node_id(&self) -> NodeId { - 0 - } - - fn peek_node_id(&self) -> NodeId { - 0 - } -} - -#[cfg(test)] -fn mk_ctxt() -> parse::ParseSess { - parse::ParseSess::new() -} - -#[cfg(test)] -fn roundtrip(in_item: hir::Item) { - let mut wr = Cursor::new(Vec::new()); - encode_item_ast(&mut Encoder::new(&mut wr), &in_item); - let rbml_doc = rbml::Doc::new(wr.get_ref()); - let out_item = decode_item_ast(rbml_doc); - - assert!(in_item == out_item); -} - -#[test] -fn test_basic() { - let cx = mk_ctxt(); - let fnia = FakeNodeIdAssigner; - let lcx = LoweringContext::new(&fnia, None); - roundtrip(lower_item(&lcx, "e_item!(&cx, - fn foo() {} - ).unwrap())); -} - -#[test] -fn test_smalltalk() { - let cx = mk_ctxt(); - let fnia = FakeNodeIdAssigner; - let lcx = LoweringContext::new(&fnia, None); - roundtrip(lower_item(&lcx, "e_item!(&cx, - fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed. - ).unwrap())); -} - -#[test] -fn test_more() { - let cx = mk_ctxt(); - let fnia = FakeNodeIdAssigner; - let lcx = LoweringContext::new(&fnia, None); - roundtrip(lower_item(&lcx, "e_item!(&cx, - fn foo(x: usize, y: usize) -> usize { - let z = x + y; - return z; - } - ).unwrap())); -} - -#[test] -fn test_simplification() { - let cx = mk_ctxt(); - let item = quote_item!(&cx, - fn new_int_alist() -> alist { - fn eq_int(a: isize, b: isize) -> bool { a == b } - return alist {eq_fn: eq_int, data: Vec::new()}; - } - ).unwrap(); - let fnia = FakeNodeIdAssigner; - let lcx = LoweringContext::new(&fnia, None); - let hir_item = lower_item(&lcx, &item); - let item_in = InlinedItemRef::Item(&hir_item); - let item_out = simplify_ast(item_in); - let item_exp = InlinedItem::Item(P(lower_item(&lcx, "e_item!(&cx, - fn new_int_alist() -> alist { - return alist {eq_fn: eq_int, data: Vec::new()}; - } - ).unwrap()))); - match (item_out, item_exp) { - (InlinedItem::Item(item_out), InlinedItem::Item(item_exp)) => { - assert!(pprust::item_to_string(&*item_out) == - pprust::item_to_string(&*item_exp)); - } - _ => panic!() - } -} diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 63134a8766d..21ece8f381e 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -16,7 +16,7 @@ use self::EvalHint::*; use front::map as ast_map; use front::map::blocks::FnLikeNode; -use metadata::util::{self as mdutil, CrateStore, InlinedItem}; +use middle::cstore::{self, CrateStore, InlinedItem}; use middle::{def, infer, subst, traits}; use middle::def_id::DefId; use middle::pat_util::def_to_path; @@ -145,11 +145,11 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, } let mut used_ref_id = false; let expr_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { - mdutil::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node { + cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node { hir::ItemConst(_, ref const_expr) => Some(const_expr.id), _ => None }, - mdutil::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node { + cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node { hir::ConstTraitItem(_, _) => { used_ref_id = true; match maybe_ref_id { @@ -168,7 +168,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, } _ => None }, - mdutil::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node { + cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node { hir::ImplItemKind::Const(_, ref expr) => Some(expr.id), _ => None }, @@ -200,8 +200,8 @@ fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: DefId) } let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { - mdutil::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id), - mdutil::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id), + cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id), + cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id), _ => None }; tcx.extern_const_fns.borrow_mut().insert(def_id, diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs new file mode 100644 index 00000000000..ee337f02ffc --- /dev/null +++ b/src/librustc/middle/cstore.rs @@ -0,0 +1,277 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// the rustc crate store interface. This also includes types that +// are *mostly* used as a part of that interface, but these should +// probably get a better home if someone can find one. + +use back::svh::Svh; +use front::map as hir_map; +use middle::def; +use middle::lang_items; +use middle::ty::{self, Ty}; +use middle::def_id::{DefId, DefIndex}; +use session::Session; +use session::search_paths::PathKind; +use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; +use std::any::Any; +use std::cell::RefCell; +use std::rc::Rc; +use std::path::PathBuf; +use syntax::ast; +use syntax::ast_util::{IdVisitingOperation}; +use syntax::attr; +use syntax::codemap::Span; +use syntax::ptr::P; +use rustc_back::target::Target; +use rustc_front::hir; +use rustc_front::visit::Visitor; +use rustc_front::util::IdVisitor; + +pub use self::DefLike::{DlDef, DlField, DlImpl}; +pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; + +// lonely orphan structs and enums looking for a better home + +#[derive(Clone, Debug)] +pub struct LinkMeta { + pub crate_name: String, + pub crate_hash: Svh, +} + +// Where a crate came from on the local filesystem. One of these two options +// must be non-None. +#[derive(PartialEq, Clone, Debug)] +pub struct CrateSource { + pub dylib: Option<(PathBuf, PathKind)>, + pub rlib: Option<(PathBuf, PathKind)>, + pub cnum: ast::CrateNum, +} + +#[derive(Copy, Debug, PartialEq, Clone)] +pub enum LinkagePreference { + RequireDynamic, + RequireStatic, +} + +enum_from_u32! { + #[derive(Copy, Clone, PartialEq)] + pub enum NativeLibraryKind { + NativeStatic, // native static library (.a archive) + NativeFramework, // OSX-specific + NativeUnknown, // default way to specify a dynamic library + } +} + +// Something that a name can resolve to. +#[derive(Copy, Clone, Debug)] +pub enum DefLike { + DlDef(def::Def), + DlImpl(DefId), + DlField +} + +/// The data we save and restore about an inlined item or method. This is not +/// part of the AST that we parse from a file, but it becomes part of the tree +/// that we trans. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum InlinedItem { + Item(P), + TraitItem(DefId /* impl id */, P), + ImplItem(DefId /* impl id */, P), + Foreign(P), +} + +/// A borrowed version of `hir::InlinedItem`. +pub enum InlinedItemRef<'a> { + Item(&'a hir::Item), + TraitItem(DefId, &'a hir::TraitItem), + ImplItem(DefId, &'a hir::ImplItem), + Foreign(&'a hir::ForeignItem) +} + +/// Item definitions in the currently-compiled crate would have the CrateNum +/// LOCAL_CRATE in their DefId. +pub const LOCAL_CRATE: ast::CrateNum = 0; + +pub struct ChildItem { + pub def: DefLike, + pub name: ast::Name, + pub vis: hir::Visibility +} + +pub enum FoundAst<'ast> { + Found(&'ast InlinedItem), + FoundParent(DefId, &'ast InlinedItem), + NotFound, +} + +pub trait CrateStore<'tcx> : Any { + // item info + fn stability(&self, def: DefId) -> Option; + fn closure_kind(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) + -> ty::ClosureKind; + fn closure_ty(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) + -> ty::ClosureTy<'tcx>; + fn item_variances(&self, def: DefId) -> ty::ItemVariances; + fn repr_attrs(&self, def: DefId) -> Vec; + fn item_type(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> ty::TypeScheme<'tcx>; + fn item_path(&self, def: DefId) -> Vec; + fn item_name(&self, def: DefId) -> ast::Name; + fn item_predicates(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> ty::GenericPredicates<'tcx>; + fn item_super_predicates(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> ty::GenericPredicates<'tcx>; + fn item_attrs(&self, def_id: DefId) -> Vec; + fn item_symbol(&self, def: DefId) -> String; + fn trait_def(&self, tcx: &ty::ctxt<'tcx>, def: DefId)-> ty::TraitDef<'tcx>; + fn adt_def(&self, tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>; + fn method_arg_names(&self, did: DefId) -> Vec; + fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec; + + // trait info + fn implementations_of_trait(&self, def_id: DefId) -> Vec; + fn provided_trait_methods(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Vec>>; + fn trait_item_def_ids(&self, def: DefId) + -> Vec; + + // impl info + fn impl_items(&self, impl_def_id: DefId) -> Vec; + fn impl_trait_ref(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Option>; + fn impl_polarity(&self, def: DefId) -> Option; + fn custom_coerce_unsized_kind(&self, def: DefId) + -> Option; + fn associated_consts(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Vec>>; + + // trait/impl-item info + fn trait_of_item(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) + -> Option; + fn impl_or_trait_item(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> ty::ImplOrTraitItem<'tcx>; + + // flags + fn is_const_fn(&self, did: DefId) -> bool; + fn is_defaulted_trait(&self, did: DefId) -> bool; + fn is_impl(&self, did: DefId) -> bool; + fn is_default_impl(&self, impl_did: DefId) -> bool; + fn is_extern_fn(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool; + fn is_static(&self, did: DefId) -> bool; + fn is_static_method(&self, did: DefId) -> bool; + fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; + fn is_typedef(&self, did: DefId) -> bool; + + // crate metadata + fn dylib_dependency_formats(&self, cnum: ast::CrateNum) + -> Vec<(ast::CrateNum, LinkagePreference)>; + fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)>; + fn missing_lang_items(&self, cnum: ast::CrateNum) -> Vec; + fn is_staged_api(&self, cnum: ast::CrateNum) -> bool; + fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; + fn is_allocator(&self, cnum: ast::CrateNum) -> bool; + fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; + fn crate_name(&self, cnum: ast::CrateNum) -> String; + fn crate_hash(&self, cnum: ast::CrateNum) -> Svh; + fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) + -> FnvHashMap>; + fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option; + fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>; + fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec; + + // resolve + fn def_path(&self, def: DefId) -> hir_map::DefPath; + fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; + fn struct_field_names(&self, def: DefId) -> Vec; + fn item_children(&self, did: DefId) -> Vec; + fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec; + + // misc. metadata + fn maybe_get_item_ast(&'tcx self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> FoundAst<'tcx>; + // This is basically a 1-based range of ints, which is a little + // silly - I may fix that. + fn crates(&self) -> Vec; + fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>; + fn used_link_args(&self) -> Vec; + + // utility functions + fn metadata_filename(&self) -> &str; + fn metadata_section_name(&self, target: &Target) -> &str; + fn encode_type(&self, tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Vec; + fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)>; + fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource; + fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; + fn encode_metadata(&self, + tcx: &ty::ctxt<'tcx>, + reexports: &def::ExportMap, + item_symbols: &RefCell>, + link_meta: &LinkMeta, + reachable: &NodeSet, + krate: &hir::Crate) -> Vec; + fn metadata_encoding_version(&self) -> &[u8]; +} + +impl InlinedItem { + pub fn visit<'ast,V>(&'ast self, visitor: &mut V) + where V: Visitor<'ast> + { + match *self { + InlinedItem::Item(ref i) => visitor.visit_item(&**i), + InlinedItem::Foreign(ref i) => visitor.visit_foreign_item(&**i), + InlinedItem::TraitItem(_, ref ti) => visitor.visit_trait_item(ti), + InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii), + } + } + + pub fn visit_ids(&self, operation: &mut O) { + let mut id_visitor = IdVisitor { + operation: operation, + pass_through_items: true, + visited_outermost: false, + }; + self.visit(&mut id_visitor); + } +} + +// FIXME: find a better place for this? +pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { + let say = |s: &str| { + match (sp, sess) { + (_, None) => panic!("{}", s), + (Some(sp), Some(sess)) => sess.span_err(sp, s), + (None, Some(sess)) => sess.err(s), + } + }; + if s.is_empty() { + say("crate name must not be empty"); + } + for c in s.chars() { + if c.is_alphanumeric() { continue } + if c == '_' { continue } + say(&format!("invalid character `{}` in crate name: `{}`", c, s)); + } + match sess { + Some(sess) => sess.abort_if_errors(), + None => {} + } +} diff --git a/src/librustc/middle/def_id.rs b/src/librustc/middle/def_id.rs index 288eb01ebb4..4d0005f47c4 100644 --- a/src/librustc/middle/def_id.rs +++ b/src/librustc/middle/def_id.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use metadata::cstore::LOCAL_CRATE; +use middle::cstore::LOCAL_CRATE; use middle::ty; use syntax::ast::CrateNum; use std::fmt; diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 229ed5984b0..ab5153e1a61 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -65,8 +65,8 @@ use syntax::ast; use session; use session::config; -use metadata::util::CrateStore; -use metadata::util::LinkagePreference::{self, RequireStatic, RequireDynamic}; +use middle::cstore::CrateStore; +use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; use util::nodemap::FnvHashMap; /// A list of dependencies for a certain crate type. diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 5101e69204d..5563cd80438 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -76,7 +76,7 @@ use front::map as ast_map; use rustc_front::hir; use rustc_front::print::pprust; -use metadata::util::CrateStore; +use middle::cstore::CrateStore; use middle::def; use middle::def_id::DefId; use middle::infer::{self, TypeOrigin}; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index c9be73892e4..ec55daca9ec 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -23,7 +23,7 @@ pub use self::LangItem::*; use front::map as hir_map; use session::Session; -use metadata::util::CrateStore; +use middle::cstore::CrateStore; use middle::def_id::DefId; use middle::ty; use middle::weak_lang_items; diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 45b8ac4a16d..e3504b6a744 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -16,10 +16,10 @@ //! Most of the documentation on regions can be found in //! `middle/typeck/infer/region_inference.rs` -use metadata::inline::InlinedItem; use front::map as ast_map; use session::Session; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; +use middle::cstore::InlinedItem; use middle::ty::{self, Ty}; use std::cell::RefCell; diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f70dce90fed..0d92c3da83c 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -15,8 +15,7 @@ pub use self::StabilityLevel::*; use session::Session; use lint; -use metadata::cstore::LOCAL_CRATE; -use metadata::util::CrateStore; +use middle::cstore::{CrateStore, LOCAL_CRATE}; use middle::def; use middle::def_id::{CRATE_DEF_INDEX, DefId}; use middle::ty; diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 705cb97a898..56dc259b1c2 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,7 +17,7 @@ use super::PredicateObligation; use super::project; use super::util; -use metadata::cstore::LOCAL_CRATE; +use middle::cstore::LOCAL_CRATE; use middle::def_id::DefId; use middle::subst::{Subst, Substs, TypeSpace}; use middle::ty::{self, Ty}; diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 105abe15509..4b614539921 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -16,8 +16,8 @@ use front::map as ast_map; use session::Session; use lint; -use metadata::util::CrateStore; use middle; +use middle::cstore::CrateStore; use middle::def::DefMap; use middle::def_id::DefId; use middle::free_region::FreeRegionMap; diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index bedff8b9a8a..71ae8e40b45 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -21,9 +21,8 @@ pub use self::LvaluePreference::*; use front::map as ast_map; use front::map::LinkedPath; -use metadata::cstore::LOCAL_CRATE; -use metadata::util::CrateStore; use middle; +use middle::cstore::{CrateStore, LOCAL_CRATE}; use middle::def::{self, ExportMap}; use middle::def_id::DefId; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index a6c2fd08e87..78cdc99f047 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -12,7 +12,7 @@ use session::config; use session::Session; -use metadata::util::CrateStore; +use middle::cstore::CrateStore; use middle::lang_items; use syntax::ast; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 4781992b987..5d691af49dc 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -22,7 +22,7 @@ use session::search_paths::SearchPaths; use rustc_back::target::Target; use lint; -use metadata::cstore; +use middle::cstore; use syntax::ast::{self, IntTy, UintTy}; use syntax::attr; diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs new file mode 100644 index 00000000000..09c6b54d99c --- /dev/null +++ b/src/librustc/session/filesearch.rs @@ -0,0 +1,207 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] + +pub use self::FileMatch::*; + +use std::collections::HashSet; +use std::env; +use std::fs; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; + +use session::search_paths::{SearchPaths, PathKind}; +use util::fs as rustcfs; + +#[derive(Copy, Clone)] +pub enum FileMatch { + FileMatches, + FileDoesntMatch, +} + +// A module for searching for libraries +// FIXME (#2658): I'm not happy how this module turned out. Should +// probably just be folded into cstore. + +pub struct FileSearch<'a> { + pub sysroot: &'a Path, + pub search_paths: &'a SearchPaths, + pub triple: &'a str, + pub kind: PathKind, +} + +impl<'a> FileSearch<'a> { + pub fn for_each_lib_search_path(&self, mut f: F) where + F: FnMut(&Path, PathKind) + { + let mut visited_dirs = HashSet::new(); + + for (path, kind) in self.search_paths.iter(self.kind) { + f(path, kind); + visited_dirs.insert(path.to_path_buf()); + } + + debug!("filesearch: searching lib path"); + let tlib_path = make_target_lib_path(self.sysroot, + self.triple); + if !visited_dirs.contains(&tlib_path) { + f(&tlib_path, PathKind::All); + } + + visited_dirs.insert(tlib_path); + } + + pub fn get_lib_path(&self) -> PathBuf { + make_target_lib_path(self.sysroot, self.triple) + } + + pub fn search(&self, mut pick: F) + where F: FnMut(&Path, PathKind) -> FileMatch + { + self.for_each_lib_search_path(|lib_search_path, kind| { + debug!("searching {}", lib_search_path.display()); + match fs::read_dir(lib_search_path) { + Ok(files) => { + let files = files.filter_map(|p| p.ok().map(|s| s.path())) + .collect::>(); + fn is_rlib(p: &Path) -> bool { + p.extension().and_then(|s| s.to_str()) == Some("rlib") + } + // Reading metadata out of rlibs is faster, and if we find both + // an rlib and a dylib we only read one of the files of + // metadata, so in the name of speed, bring all rlib files to + // the front of the search list. + let files1 = files.iter().filter(|p| is_rlib(p)); + let files2 = files.iter().filter(|p| !is_rlib(p)); + for path in files1.chain(files2) { + debug!("testing {}", path.display()); + let maybe_picked = pick(path, kind); + match maybe_picked { + FileMatches => { + debug!("picked {}", path.display()); + } + FileDoesntMatch => { + debug!("rejected {}", path.display()); + } + } + } + } + Err(..) => (), + } + }); + } + + pub fn new(sysroot: &'a Path, + triple: &'a str, + search_paths: &'a SearchPaths, + kind: PathKind) -> FileSearch<'a> { + debug!("using sysroot = {}, triple = {}", sysroot.display(), triple); + FileSearch { + sysroot: sysroot, + search_paths: search_paths, + triple: triple, + kind: kind, + } + } + + // Returns a list of directories where target-specific dylibs might be located. + pub fn get_dylib_search_paths(&self) -> Vec { + let mut paths = Vec::new(); + self.for_each_lib_search_path(|lib_search_path, _| { + paths.push(lib_search_path.to_path_buf()); + }); + paths + } + + // Returns a list of directories where target-specific tool binaries are located. + pub fn get_tools_search_paths(&self) -> Vec { + let mut p = PathBuf::from(self.sysroot); + p.push(&find_libdir(self.sysroot)); + p.push(&rustlibdir()); + p.push(&self.triple); + p.push("bin"); + vec![p] + } +} + +pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { + let mut p = PathBuf::from(&find_libdir(sysroot)); + assert!(p.is_relative()); + p.push(&rustlibdir()); + p.push(target_triple); + p.push("lib"); + p +} + +fn make_target_lib_path(sysroot: &Path, + target_triple: &str) -> PathBuf { + sysroot.join(&relative_target_lib_path(sysroot, target_triple)) +} + +pub fn get_or_default_sysroot() -> PathBuf { + // Follow symlinks. If the resolved path is relative, make it absolute. + fn canonicalize(path: Option) -> Option { + path.and_then(|path| { + match fs::canonicalize(&path) { + // See comments on this target function, but the gist is that + // gcc chokes on verbatim paths which fs::canonicalize generates + // so we try to avoid those kinds of paths. + Ok(canon) => Some(rustcfs::fix_windows_verbatim_for_gcc(&canon)), + Err(e) => panic!("failed to get realpath: {}", e), + } + }) + } + + match canonicalize(env::current_exe().ok()) { + Some(mut p) => { p.pop(); p.pop(); p } + None => panic!("can't determine value for sysroot") + } +} + +// The name of the directory rustc expects libraries to be located. +fn find_libdir(sysroot: &Path) -> String { + // FIXME: This is a quick hack to make the rustc binary able to locate + // Rust libraries in Linux environments where libraries might be installed + // to lib64/lib32. This would be more foolproof by basing the sysroot off + // of the directory where librustc is located, rather than where the rustc + // binary is. + //If --libdir is set during configuration to the value other than + // "lib" (i.e. non-default), this value is used (see issue #16552). + + match option_env!("CFG_LIBDIR_RELATIVE") { + Some(libdir) if libdir != "lib" => return libdir.to_string(), + _ => if sysroot.join(&primary_libdir_name()).join(&rustlibdir()).exists() { + return primary_libdir_name(); + } else { + return secondary_libdir_name(); + } + } + + #[cfg(target_pointer_width = "64")] + fn primary_libdir_name() -> String { + "lib64".to_string() + } + + #[cfg(target_pointer_width = "32")] + fn primary_libdir_name() -> String { + "lib32".to_string() + } + + fn secondary_libdir_name() -> String { + "lib".to_string() + } +} + +// The name of rustc's own place to organize libraries. +// Used to be "rustc", now the default is "rustlib" +pub fn rustlibdir() -> String { + "rustlib".to_string() +} diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index bf9c4c8bca6..7bf96b41dce 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -9,8 +9,7 @@ // except according to those terms. use lint; -use metadata::filesearch; -use metadata::util::CrateStore; +use middle::cstore::CrateStore; use middle::dependency_format; use session::search_paths::PathKind; use util::nodemap::{NodeMap, FnvHashMap}; @@ -34,6 +33,7 @@ use std::env; use std::rc::Rc; pub mod config; +pub mod filesearch; pub mod search_paths; // Represents the data associated with a compilation diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d00b08538d2..1429a6a54a6 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -16,9 +16,6 @@ use rustc::session::Session; use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; -use rustc::metadata; -use rustc::metadata::creader::LocalCrateReader; -use rustc::metadata::cstore::CStore; use rustc::middle::{stability, ty, reachable}; use rustc::middle::dependency_format; use rustc::middle; @@ -26,6 +23,9 @@ use rustc::util::nodemap::NodeMap; use rustc::util::common::time; use rustc_borrowck as borrowck; use rustc_resolve as resolve; +use rustc_metadata::macro_import; +use rustc_metadata::creader::LocalCrateReader; +use rustc_metadata::cstore::CStore; use rustc_trans::back::link; use rustc_trans::back::write; use rustc_trans::trans; @@ -482,7 +482,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, let macros = time(time_passes, "macro loading", - || metadata::macro_import::read_macro_defs(sess, &cstore, &krate)); + || macro_import::read_macro_defs(sess, &cstore, &krate)); let mut addl_plugins = Some(addl_plugins); let registrars = time(time_passes, "plugin loading", || { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fdbb093eab0..b77425e1809 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -47,6 +47,7 @@ extern crate rustc_front; extern crate rustc_lint; extern crate rustc_plugin; extern crate rustc_privacy; +extern crate rustc_metadata; extern crate rustc_mir; extern crate rustc_resolve; extern crate rustc_trans; @@ -68,11 +69,11 @@ use rustc_trans::back::link; use rustc_trans::save; use rustc::session::{config, Session, build_session}; use rustc::session::config::{Input, PrintRequest, OutputType}; +use rustc::middle::cstore::CrateStore; use rustc::lint::Lint; use rustc::lint; -use rustc::metadata; -use rustc::metadata::cstore::CStore; -use rustc::metadata::util::CrateStore; +use rustc_metadata::loader; +use rustc_metadata::cstore::CStore; use rustc::util::common::time; use std::cmp::Ordering::Equal; @@ -448,7 +449,7 @@ impl RustcDefaultCalls { &Input::File(ref ifile) => { let path = &(*ifile); let mut v = Vec::new(); - metadata::loader::list_file_metadata(&sess.target.target, path, &mut v) + loader::list_file_metadata(&sess.target.target, path, &mut v) .unwrap(); println!("{}", String::from_utf8(v).unwrap()); } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index ddd5f931a80..630c42db68c 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -19,7 +19,6 @@ use rustc_trans::back::link; use driver; -use rustc::metadata::cstore::CStore; use rustc::middle::ty; use rustc::middle::cfg; use rustc::middle::cfg::graphviz::LabelledCFG; @@ -28,6 +27,7 @@ use rustc::session::config::Input; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; use rustc_resolve as resolve; +use rustc_metadata::cstore::CStore; use syntax::ast; use syntax::codemap; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 7327170c52b..739c5f12ecb 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -29,11 +29,11 @@ //! a `pub fn new()`. use middle::{cfg, def, infer, stability, traits}; +use middle::cstore::CrateStore; use middle::def_id::DefId; use middle::subst::Substs; use middle::ty::{self, Ty}; use middle::ty::adjustment; -use rustc::metadata::util::CrateStore; use rustc::front::map as hir_map; use util::nodemap::{NodeSet}; use lint::{Level, LateContext, LintContext, LintArray, Lint}; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index d48dbdc5f51..1d7431404f5 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -50,7 +50,6 @@ extern crate rustc_front; extern crate rustc_back; pub use rustc::lint as lint; -pub use rustc::metadata as metadata; pub use rustc::middle as middle; pub use rustc::session as session; pub use rustc::util as util; diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs new file mode 100644 index 00000000000..2ecf715424b --- /dev/null +++ b/src/librustc_metadata/astencode.rs @@ -0,0 +1,1472 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] +// FIXME: remove this after snapshot, and Results are handled +#![allow(unused_must_use)] + +use rustc::front::map as ast_map; +use rustc::session::Session; + +use rustc_front::hir; +use rustc_front::fold; +use rustc_front::fold::Folder; + +use common as c; +use cstore; +use decoder; +use encoder as e; +use tydecode; +use tyencode; + +use middle::cstore::{InlinedItem, InlinedItemRef}; +use middle::ty::adjustment; +use middle::ty::cast; +use middle::check_const::ConstQualif; +use middle::def; +use middle::def_id::DefId; +use middle::privacy::{AllPublic, LastMod}; +use middle::region; +use middle::subst; +use middle::ty::{self, Ty}; + +use syntax::{ast, ast_util, codemap}; +use syntax::ast::NodeIdAssigner; +use syntax::codemap::Span; +use syntax::ptr::P; + +use std::cell::Cell; +use std::io::SeekFrom; +use std::io::prelude::*; +use std::fmt::Debug; + +use rbml::reader; +use rbml::writer::Encoder; +use rbml; +use serialize; +use serialize::{Decodable, Decoder, DecoderHelpers, Encodable}; +use serialize::EncoderHelpers; + +#[cfg(test)] use std::io::Cursor; +#[cfg(test)] use syntax::parse; +#[cfg(test)] use syntax::ast::NodeId; +#[cfg(test)] use rustc_front::print::pprust; +#[cfg(test)] use rustc_front::lowering::{lower_item, LoweringContext}; + +struct DecodeContext<'a, 'b, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, + cdata: &'b cstore::crate_metadata, + from_id_range: ast_util::IdRange, + to_id_range: ast_util::IdRange, + // Cache the last used filemap for translating spans as an optimization. + last_filemap_index: Cell, +} + +trait tr { + fn tr(&self, dcx: &DecodeContext) -> Self; +} + +// ______________________________________________________________________ +// Top-level methods. + +pub fn encode_inlined_item(ecx: &e::EncodeContext, + rbml_w: &mut Encoder, + ii: InlinedItemRef) { + let id = match ii { + InlinedItemRef::Item(i) => i.id, + InlinedItemRef::Foreign(i) => i.id, + InlinedItemRef::TraitItem(_, ti) => ti.id, + InlinedItemRef::ImplItem(_, ii) => ii.id, + }; + debug!("> Encoding inlined item: {} ({:?})", + ecx.tcx.map.path_to_string(id), + rbml_w.writer.seek(SeekFrom::Current(0))); + + // Folding could be avoided with a smarter encoder. + let ii = simplify_ast(ii); + let id_range = inlined_item_id_range(&ii); + + rbml_w.start_tag(c::tag_ast as usize); + id_range.encode(rbml_w); + encode_ast(rbml_w, &ii); + encode_side_tables_for_ii(ecx, rbml_w, &ii); + rbml_w.end_tag(); + + debug!("< Encoded inlined fn: {} ({:?})", + ecx.tcx.map.path_to_string(id), + rbml_w.writer.seek(SeekFrom::Current(0))); +} + +impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> { + fn new_id(&self, id: ast::NodeId) -> ast::NodeId { + if id == ast::DUMMY_NODE_ID { + // Used by ast_map to map the NodeInlinedParent. + self.tcx.sess.next_node_id() + } else { + self.tr_id(id) + } + } + fn new_def_id(&self, def_id: DefId) -> DefId { + self.tr_def_id(def_id) + } + fn new_span(&self, span: Span) -> Span { + self.tr_span(span) + } +} + +/// Decodes an item from its AST in the cdata's metadata and adds it to the +/// ast-map. +pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, + tcx: &ty::ctxt<'tcx>, + path: Vec, + def_path: ast_map::DefPath, + par_doc: rbml::Doc, + orig_did: DefId) + -> Result<&'tcx InlinedItem, (Vec, + ast_map::DefPath)> { + match par_doc.opt_child(c::tag_ast) { + None => Err((path, def_path)), + Some(ast_doc) => { + let mut path_as_str = None; + debug!("> Decoding inlined fn: {:?}::?", + { + // Do an Option dance to use the path after it is moved below. + let s = ast_map::path_to_string(path.iter().cloned()); + path_as_str = Some(s); + path_as_str.as_ref().map(|x| &x[..]) + }); + let mut ast_dsr = reader::Decoder::new(ast_doc); + let from_id_range = Decodable::decode(&mut ast_dsr).unwrap(); + let to_id_range = reserve_id_range(&tcx.sess, from_id_range); + let dcx = &DecodeContext { + cdata: cdata, + tcx: tcx, + from_id_range: from_id_range, + to_id_range: to_id_range, + last_filemap_index: Cell::new(0) + }; + let raw_ii = decode_ast(ast_doc); + let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, def_path, raw_ii, dcx); + + let name = match *ii { + InlinedItem::Item(ref i) => i.name, + InlinedItem::Foreign(ref i) => i.name, + InlinedItem::TraitItem(_, ref ti) => ti.name, + InlinedItem::ImplItem(_, ref ii) => ii.name + }; + debug!("Fn named: {}", name); + debug!("< Decoded inlined fn: {}::{}", + path_as_str.unwrap(), + name); + region::resolve_inlined_item(&tcx.sess, &tcx.region_maps, ii); + decode_side_tables(dcx, ast_doc); + copy_item_types(dcx, ii, orig_did); + match *ii { + InlinedItem::Item(ref i) => { + debug!(">>> DECODED ITEM >>>\n{}\n<<< DECODED ITEM <<<", + ::rustc_front::print::pprust::item_to_string(&**i)); + } + _ => { } + } + Ok(ii) + } + } +} + +// ______________________________________________________________________ +// Enumerating the IDs which appear in an AST + +fn reserve_id_range(sess: &Session, + from_id_range: ast_util::IdRange) -> ast_util::IdRange { + // Handle the case of an empty range: + if from_id_range.empty() { return from_id_range; } + let cnt = from_id_range.max - from_id_range.min; + let to_id_min = sess.reserve_node_ids(cnt); + let to_id_max = to_id_min + cnt; + ast_util::IdRange { min: to_id_min, max: to_id_max } +} + +impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> { + /// Translates an internal id, meaning a node id that is known to refer to some part of the + /// item currently being inlined, such as a local variable or argument. All naked node-ids + /// that appear in types have this property, since if something might refer to an external item + /// we would use a def-id to allow for the possibility that the item resides in another crate. + pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId { + // from_id_range should be non-empty + assert!(!self.from_id_range.empty()); + // Use wrapping arithmetic because otherwise it introduces control flow. + // Maybe we should just have the control flow? -- aatch + (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min)) + } + + /// Translates an EXTERNAL def-id, converting the crate number from the one used in the encoded + /// data to the current crate numbers.. By external, I mean that it be translated to a + /// reference to the item in its original crate, as opposed to being translated to a reference + /// to the inlined version of the item. This is typically, but not always, what you want, + /// because most def-ids refer to external things like types or other fns that may or may not + /// be inlined. Note that even when the inlined function is referencing itself recursively, we + /// would want `tr_def_id` for that reference--- conceptually the function calls the original, + /// non-inlined version, and trans deals with linking that recursive call to the inlined copy. + pub fn tr_def_id(&self, did: DefId) -> DefId { + decoder::translate_def_id(self.cdata, did) + } + + /// Translates a `Span` from an extern crate to the corresponding `Span` + /// within the local crate's codemap. `creader::import_codemap()` will + /// already have allocated any additionally needed FileMaps in the local + /// codemap as a side-effect of creating the crate_metadata's + /// `codemap_import_info`. + pub fn tr_span(&self, span: Span) -> Span { + let span = if span.lo > span.hi { + // Currently macro expansion sometimes produces invalid Span values + // where lo > hi. In order not to crash the compiler when trying to + // translate these values, let's transform them into something we + // can handle (and which will produce useful debug locations at + // least some of the time). + // This workaround is only necessary as long as macro expansion is + // not fixed. FIXME(#23480) + codemap::mk_sp(span.lo, span.lo) + } else { + span + }; + + let imported_filemaps = self.cdata.imported_filemaps(self.tcx.sess.codemap()); + let filemap = { + // Optimize for the case that most spans within a translated item + // originate from the same filemap. + let last_filemap_index = self.last_filemap_index.get(); + let last_filemap = &imported_filemaps[last_filemap_index]; + + if span.lo >= last_filemap.original_start_pos && + span.lo <= last_filemap.original_end_pos && + span.hi >= last_filemap.original_start_pos && + span.hi <= last_filemap.original_end_pos { + last_filemap + } else { + let mut a = 0; + let mut b = imported_filemaps.len(); + + while b - a > 1 { + let m = (a + b) / 2; + if imported_filemaps[m].original_start_pos > span.lo { + b = m; + } else { + a = m; + } + } + + self.last_filemap_index.set(a); + &imported_filemaps[a] + } + }; + + let lo = (span.lo - filemap.original_start_pos) + + filemap.translated_filemap.start_pos; + let hi = (span.hi - filemap.original_start_pos) + + filemap.translated_filemap.start_pos; + + codemap::mk_sp(lo, hi) + } +} + +impl tr for DefId { + fn tr(&self, dcx: &DecodeContext) -> DefId { + dcx.tr_def_id(*self) + } +} + +impl tr for Option { + fn tr(&self, dcx: &DecodeContext) -> Option { + self.map(|d| dcx.tr_def_id(d)) + } +} + +impl tr for Span { + fn tr(&self, dcx: &DecodeContext) -> Span { + dcx.tr_span(*self) + } +} + +trait def_id_encoder_helpers { + fn emit_def_id(&mut self, did: DefId); +} + +impl def_id_encoder_helpers for S + where ::Error: Debug +{ + fn emit_def_id(&mut self, did: DefId) { + did.encode(self).unwrap() + } +} + +trait def_id_decoder_helpers { + fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId; + fn read_def_id_nodcx(&mut self, + cdata: &cstore::crate_metadata) -> DefId; +} + +impl def_id_decoder_helpers for D + where ::Error: Debug +{ + fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId { + let did: DefId = Decodable::decode(self).unwrap(); + did.tr(dcx) + } + + fn read_def_id_nodcx(&mut self, + cdata: &cstore::crate_metadata) + -> DefId { + let did: DefId = Decodable::decode(self).unwrap(); + decoder::translate_def_id(cdata, did) + } +} + +// ______________________________________________________________________ +// Encoding and decoding the AST itself +// +// When decoding, we have to renumber the AST so that the node ids that +// appear within are disjoint from the node ids in our existing ASTs. +// We also have to adjust the spans: for now we just insert a dummy span, +// but eventually we should add entries to the local codemap as required. + +fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) { + rbml_w.start_tag(c::tag_tree as usize); + item.encode(rbml_w); + rbml_w.end_tag(); +} + +struct NestedItemsDropper; + +impl Folder for NestedItemsDropper { + fn fold_block(&mut self, blk: P) -> P { + blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| { + let stmts_sans_items = stmts.into_iter().filter_map(|stmt| { + let use_stmt = match stmt.node { + hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true, + hir::StmtDecl(ref decl, _) => { + match decl.node { + hir::DeclLocal(_) => true, + hir::DeclItem(_) => false, + } + } + }; + if use_stmt { + Some(stmt) + } else { + None + } + }).collect(); + let blk_sans_items = P(hir::Block { + stmts: stmts_sans_items, + expr: expr, + id: id, + rules: rules, + span: span, + }); + fold::noop_fold_block(blk_sans_items, self) + }) + } +} + +// Produces a simplified copy of the AST which does not include things +// that we do not need to or do not want to export. For example, we +// do not include any nested items: if these nested items are to be +// inlined, their AST will be exported separately (this only makes +// sense because, in Rust, nested items are independent except for +// their visibility). +// +// As it happens, trans relies on the fact that we do not export +// nested items, as otherwise it would get confused when translating +// inlined items. +fn simplify_ast(ii: InlinedItemRef) -> InlinedItem { + let mut fld = NestedItemsDropper; + + match ii { + // HACK we're not dropping items. + InlinedItemRef::Item(i) => { + InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld))) + } + InlinedItemRef::TraitItem(d, ti) => { + InlinedItem::TraitItem(d, fold::noop_fold_trait_item(P(ti.clone()), &mut fld)) + } + InlinedItemRef::ImplItem(d, ii) => { + InlinedItem::ImplItem(d, fold::noop_fold_impl_item(P(ii.clone()), &mut fld)) + } + InlinedItemRef::Foreign(i) => { + InlinedItem::Foreign(fold::noop_fold_foreign_item(P(i.clone()), &mut fld)) + } + } +} + +fn decode_ast(par_doc: rbml::Doc) -> InlinedItem { + let chi_doc = par_doc.get(c::tag_tree as usize); + let mut d = reader::Decoder::new(chi_doc); + Decodable::decode(&mut d).unwrap() +} + +// ______________________________________________________________________ +// Encoding and decoding of ast::def + +fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> def::Def { + let def: def::Def = Decodable::decode(dsr).unwrap(); + def.tr(dcx) +} + +impl tr for def::Def { + fn tr(&self, dcx: &DecodeContext) -> def::Def { + match *self { + def::DefFn(did, is_ctor) => def::DefFn(did.tr(dcx), is_ctor), + def::DefMethod(did) => def::DefMethod(did.tr(dcx)), + def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)), + impl_ids.map(|(nid1, nid2)| { + (dcx.tr_id(nid1), + dcx.tr_id(nid2)) + })) } + def::DefMod(did) => { def::DefMod(did.tr(dcx)) } + def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) } + def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) } + def::DefConst(did) => { def::DefConst(did.tr(dcx)) } + def::DefAssociatedConst(did) => def::DefAssociatedConst(did.tr(dcx)), + def::DefLocal(_, nid) => { + let nid = dcx.tr_id(nid); + let did = dcx.tcx.map.local_def_id(nid); + def::DefLocal(did, nid) + } + def::DefVariant(e_did, v_did, is_s) => { + def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s) + }, + def::DefTrait(did) => def::DefTrait(did.tr(dcx)), + def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum), + def::DefAssociatedTy(trait_did, did) => + def::DefAssociatedTy(trait_did.tr(dcx), did.tr(dcx)), + def::DefPrimTy(p) => def::DefPrimTy(p), + def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n), + def::DefUse(did) => def::DefUse(did.tr(dcx)), + def::DefUpvar(_, nid1, index, nid2) => { + let nid1 = dcx.tr_id(nid1); + let nid2 = dcx.tr_id(nid2); + let did1 = dcx.tcx.map.local_def_id(nid1); + def::DefUpvar(did1, nid1, index, nid2) + } + def::DefStruct(did) => def::DefStruct(did.tr(dcx)), + def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid)) + } + } +} + +// ______________________________________________________________________ +// Encoding and decoding of freevar information + +fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &ty::Freevar) { + (*fv).encode(rbml_w).unwrap(); +} + +trait rbml_decoder_helper { + fn read_freevar_entry(&mut self, dcx: &DecodeContext) + -> ty::Freevar; + fn read_capture_mode(&mut self) -> hir::CaptureClause; +} + +impl<'a> rbml_decoder_helper for reader::Decoder<'a> { + fn read_freevar_entry(&mut self, dcx: &DecodeContext) + -> ty::Freevar { + let fv: ty::Freevar = Decodable::decode(self).unwrap(); + fv.tr(dcx) + } + + fn read_capture_mode(&mut self) -> hir::CaptureClause { + let cm: hir::CaptureClause = Decodable::decode(self).unwrap(); + cm + } +} + +impl tr for ty::Freevar { + fn tr(&self, dcx: &DecodeContext) -> ty::Freevar { + ty::Freevar { + def: self.def.tr(dcx), + span: self.span.tr(dcx), + } + } +} + +// ______________________________________________________________________ +// Encoding and decoding of MethodCallee + +trait read_method_callee_helper<'tcx> { + fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> (u32, ty::MethodCallee<'tcx>); +} + +fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + autoderef: u32, + method: &ty::MethodCallee<'tcx>) { + use serialize::Encoder; + + rbml_w.emit_struct("MethodCallee", 4, |rbml_w| { + rbml_w.emit_struct_field("autoderef", 0, |rbml_w| { + autoderef.encode(rbml_w) + }); + rbml_w.emit_struct_field("def_id", 1, |rbml_w| { + Ok(rbml_w.emit_def_id(method.def_id)) + }); + rbml_w.emit_struct_field("ty", 2, |rbml_w| { + Ok(rbml_w.emit_ty(ecx, method.ty)) + }); + rbml_w.emit_struct_field("substs", 3, |rbml_w| { + Ok(rbml_w.emit_substs(ecx, &method.substs)) + }) + }).unwrap(); +} + +impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { + fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> (u32, ty::MethodCallee<'tcx>) { + + self.read_struct("MethodCallee", 4, |this| { + let autoderef = this.read_struct_field("autoderef", 0, + Decodable::decode).unwrap(); + Ok((autoderef, ty::MethodCallee { + def_id: this.read_struct_field("def_id", 1, |this| { + Ok(this.read_def_id(dcx)) + }).unwrap(), + ty: this.read_struct_field("ty", 2, |this| { + Ok(this.read_ty(dcx)) + }).unwrap(), + substs: this.read_struct_field("substs", 3, |this| { + Ok(dcx.tcx.mk_substs(this.read_substs(dcx))) + }).unwrap() + })) + }).unwrap() + } +} + +pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) { + kind.encode(ebml_w).unwrap(); +} + +// ______________________________________________________________________ +// Encoding and decoding the side tables + +trait get_ty_str_ctxt<'tcx> { + fn ty_str_ctxt<'a>(&'a self) -> tyencode::ctxt<'a, 'tcx>; +} + +impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> { + fn ty_str_ctxt<'b>(&'b self) -> tyencode::ctxt<'b, 'tcx> { + tyencode::ctxt { + diag: self.tcx.sess.diagnostic(), + ds: e::def_to_string, + tcx: self.tcx, + abbrevs: &self.type_abbrevs + } + } +} + +trait rbml_writer_helpers<'tcx> { + fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region); + fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); + fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]); + fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + predicate: &ty::Predicate<'tcx>); + fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + ty: &ty::TraitRef<'tcx>); + fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + substs: &subst::Substs<'tcx>); + fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, + bounds: &ty::ExistentialBounds<'tcx>); + fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); + fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture); + fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + adj: &adjustment::AutoAdjustment<'tcx>); + fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + autoref: &adjustment::AutoRef<'tcx>); + fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, + auto_deref_ref: &adjustment::AutoDerefRef<'tcx>); +} + +impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { + fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) { + self.emit_opaque(|this| Ok(e::write_region(ecx, this, r))); + } + + fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) { + self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty))); + } + + fn emit_tys<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, tys: &[Ty<'tcx>]) { + self.emit_from_vec(tys, |this, ty| Ok(this.emit_ty(ecx, *ty))); + } + + fn emit_trait_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, + trait_ref: &ty::TraitRef<'tcx>) { + self.emit_opaque(|this| Ok(e::write_trait_ref(ecx, this, trait_ref))); + } + + fn emit_predicate<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, + predicate: &ty::Predicate<'tcx>) { + self.emit_opaque(|this| { + Ok(tyencode::enc_predicate(this, + &ecx.ty_str_ctxt(), + predicate)) + }); + } + + fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>, + bounds: &ty::ExistentialBounds<'tcx>) { + self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this, + &ecx.ty_str_ctxt(), + bounds))); + } + + fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds) { + self.emit_opaque(|this| Ok(tyencode::enc_builtin_bounds(this, + &ecx.ty_str_ctxt(), + bounds))); + } + + fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture) { + use serialize::Encoder; + + self.emit_enum("UpvarCapture", |this| { + match *capture { + ty::UpvarCapture::ByValue => { + this.emit_enum_variant("ByValue", 1, 0, |_| Ok(())) + } + ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, region }) => { + this.emit_enum_variant("ByRef", 2, 0, |this| { + this.emit_enum_variant_arg(0, + |this| kind.encode(this)); + this.emit_enum_variant_arg(1, + |this| Ok(this.emit_region(ecx, region))) + }) + } + } + }).unwrap() + } + + fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, + substs: &subst::Substs<'tcx>) { + self.emit_opaque(|this| Ok(tyencode::enc_substs(this, + &ecx.ty_str_ctxt(), + substs))); + } + + fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, + adj: &adjustment::AutoAdjustment<'tcx>) { + use serialize::Encoder; + + self.emit_enum("AutoAdjustment", |this| { + match *adj { + adjustment::AdjustReifyFnPointer=> { + this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(())) + } + + adjustment::AdjustUnsafeFnPointer => { + this.emit_enum_variant("AdjustUnsafeFnPointer", 2, 0, |_| { + Ok(()) + }) + } + + adjustment::AdjustDerefRef(ref auto_deref_ref) => { + this.emit_enum_variant("AdjustDerefRef", 3, 2, |this| { + this.emit_enum_variant_arg(0, + |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) + }) + } + } + }); + } + + fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, + autoref: &adjustment::AutoRef<'tcx>) { + use serialize::Encoder; + + self.emit_enum("AutoRef", |this| { + match autoref { + &adjustment::AutoPtr(r, m) => { + this.emit_enum_variant("AutoPtr", 0, 2, |this| { + this.emit_enum_variant_arg(0, + |this| Ok(this.emit_region(ecx, *r))); + this.emit_enum_variant_arg(1, |this| m.encode(this)) + }) + } + &adjustment::AutoUnsafe(m) => { + this.emit_enum_variant("AutoUnsafe", 1, 1, |this| { + this.emit_enum_variant_arg(0, |this| m.encode(this)) + }) + } + } + }); + } + + fn emit_auto_deref_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, + auto_deref_ref: &adjustment::AutoDerefRef<'tcx>) { + use serialize::Encoder; + + self.emit_struct("AutoDerefRef", 2, |this| { + this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); + + this.emit_struct_field("autoref", 1, |this| { + this.emit_option(|this| { + match auto_deref_ref.autoref { + None => this.emit_option_none(), + Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), + } + }) + }); + + this.emit_struct_field("unsize", 2, |this| { + this.emit_option(|this| { + match auto_deref_ref.unsize { + None => this.emit_option_none(), + Some(target) => this.emit_option_some(|this| { + Ok(this.emit_ty(ecx, target)) + }) + } + }) + }) + }); + } +} + +trait write_tag_and_id { + fn tag(&mut self, tag_id: c::astencode_tag, f: F) where F: FnOnce(&mut Self); + fn id(&mut self, id: ast::NodeId); +} + +impl<'a> write_tag_and_id for Encoder<'a> { + fn tag(&mut self, + tag_id: c::astencode_tag, + f: F) where + F: FnOnce(&mut Encoder<'a>), + { + self.start_tag(tag_id as usize); + f(self); + self.end_tag(); + } + + fn id(&mut self, id: ast::NodeId) { + id.encode(self).unwrap(); + } +} + +struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { + ecx: &'a e::EncodeContext<'c, 'tcx>, + rbml_w: &'a mut Encoder<'b>, +} + +impl<'a, 'b, 'c, 'tcx> ast_util::IdVisitingOperation for + SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> { + fn visit_id(&mut self, id: ast::NodeId) { + encode_side_tables_for_id(self.ecx, self.rbml_w, id) + } +} + +fn encode_side_tables_for_ii(ecx: &e::EncodeContext, + rbml_w: &mut Encoder, + ii: &InlinedItem) { + rbml_w.start_tag(c::tag_table as usize); + ii.visit_ids(&mut SideTableEncodingIdVisitor { + ecx: ecx, + rbml_w: rbml_w + }); + rbml_w.end_tag(); +} + +fn encode_side_tables_for_id(ecx: &e::EncodeContext, + rbml_w: &mut Encoder, + id: ast::NodeId) { + let tcx = ecx.tcx; + + debug!("Encoding side tables for id {}", id); + + if let Some(def) = tcx.def_map.borrow().get(&id).map(|d| d.full_def()) { + rbml_w.tag(c::tag_table_def, |rbml_w| { + rbml_w.id(id); + def.encode(rbml_w).unwrap(); + }) + } + + if let Some(ty) = tcx.node_types().get(&id) { + rbml_w.tag(c::tag_table_node_type, |rbml_w| { + rbml_w.id(id); + rbml_w.emit_ty(ecx, *ty); + }) + } + + if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) { + rbml_w.tag(c::tag_table_item_subst, |rbml_w| { + rbml_w.id(id); + rbml_w.emit_substs(ecx, &item_substs.substs); + }) + } + + if let Some(fv) = tcx.freevars.borrow().get(&id) { + rbml_w.tag(c::tag_table_freevars, |rbml_w| { + rbml_w.id(id); + rbml_w.emit_from_vec(fv, |rbml_w, fv_entry| { + Ok(encode_freevar_entry(rbml_w, fv_entry)) + }); + }); + + for freevar in fv { + rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| { + rbml_w.id(id); + + let var_id = freevar.def.var_id(); + let upvar_id = ty::UpvarId { + var_id: var_id, + closure_expr_id: id + }; + let upvar_capture = tcx.tables + .borrow() + .upvar_capture_map + .get(&upvar_id) + .unwrap() + .clone(); + var_id.encode(rbml_w); + rbml_w.emit_upvar_capture(ecx, &upvar_capture); + }) + } + } + + let method_call = ty::MethodCall::expr(id); + if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { + rbml_w.tag(c::tag_table_method_map, |rbml_w| { + rbml_w.id(id); + encode_method_callee(ecx, rbml_w, method_call.autoderef, method) + }) + } + + if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) { + match *adjustment { + adjustment::AdjustDerefRef(ref adj) => { + for autoderef in 0..adj.autoderefs { + let method_call = ty::MethodCall::autoderef(id, autoderef as u32); + if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { + rbml_w.tag(c::tag_table_method_map, |rbml_w| { + rbml_w.id(id); + encode_method_callee(ecx, rbml_w, + method_call.autoderef, method) + }) + } + } + } + _ => {} + } + + rbml_w.tag(c::tag_table_adjustments, |rbml_w| { + rbml_w.id(id); + rbml_w.emit_auto_adjustment(ecx, adjustment); + }) + } + + if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) { + rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| { + rbml_w.id(id); + encode_cast_kind(rbml_w, *cast_kind) + }) + } + + if let Some(qualif) = tcx.const_qualif_map.borrow().get(&id) { + rbml_w.tag(c::tag_table_const_qualif, |rbml_w| { + rbml_w.id(id); + qualif.encode(rbml_w).unwrap() + }) + } +} + +trait doc_decoder_helpers: Sized { + fn as_int(&self) -> isize; + fn opt_child(&self, tag: c::astencode_tag) -> Option; +} + +impl<'a> doc_decoder_helpers for rbml::Doc<'a> { + fn as_int(&self) -> isize { reader::doc_as_u64(*self) as isize } + fn opt_child(&self, tag: c::astencode_tag) -> Option> { + reader::maybe_get_doc(*self, tag as usize) + } +} + +trait rbml_decoder_decoder_helpers<'tcx> { + fn read_ty_encoded<'a, 'b, F, R>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>, + f: F) -> R + where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R; + + fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region; + fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>; + fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec>; + fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> ty::TraitRef<'tcx>; + fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> ty::PolyTraitRef<'tcx>; + fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> ty::Predicate<'tcx>; + fn read_existential_bounds<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> ty::ExistentialBounds<'tcx>; + fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> subst::Substs<'tcx>; + fn read_upvar_capture(&mut self, dcx: &DecodeContext) + -> ty::UpvarCapture; + fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> adjustment::AutoAdjustment<'tcx>; + fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> cast::CastKind; + fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> adjustment::AutoDerefRef<'tcx>; + fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> adjustment::AutoRef<'tcx>; + fn convert_def_id(&mut self, + dcx: &DecodeContext, + did: DefId) + -> DefId; + + // Versions of the type reading functions that don't need the full + // DecodeContext. + fn read_ty_nodcx(&mut self, + tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) -> Ty<'tcx>; + fn read_tys_nodcx(&mut self, + tcx: &ty::ctxt<'tcx>, + cdata: &cstore::crate_metadata) -> Vec>; + fn read_substs_nodcx(&mut self, tcx: &ty::ctxt<'tcx>, + cdata: &cstore::crate_metadata) + -> subst::Substs<'tcx>; +} + +impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { + fn read_ty_nodcx(&mut self, + tcx: &ty::ctxt<'tcx>, + cdata: &cstore::crate_metadata) + -> Ty<'tcx> { + self.read_opaque(|_, doc| { + Ok( + tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc, + &mut |id| decoder::translate_def_id(cdata, id)) + .parse_ty()) + }).unwrap() + } + + fn read_tys_nodcx(&mut self, + tcx: &ty::ctxt<'tcx>, + cdata: &cstore::crate_metadata) -> Vec> { + self.read_to_vec(|this| Ok(this.read_ty_nodcx(tcx, cdata)) ) + .unwrap() + .into_iter() + .collect() + } + + fn read_substs_nodcx(&mut self, + tcx: &ty::ctxt<'tcx>, + cdata: &cstore::crate_metadata) + -> subst::Substs<'tcx> + { + self.read_opaque(|_, doc| { + Ok( + tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc, + &mut |id| decoder::translate_def_id(cdata, id)) + .parse_substs()) + }).unwrap() + } + + fn read_ty_encoded<'b, 'c, F, R>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>, op: F) -> R + where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x,'tcx>) -> R + { + return self.read_opaque(|this, doc| { + debug!("read_ty_encoded({})", type_string(doc)); + Ok(op( + &mut tydecode::TyDecoder::with_doc( + dcx.tcx, dcx.cdata.cnum, doc, + &mut |a| this.convert_def_id(dcx, a)))) + }).unwrap(); + + fn type_string(doc: rbml::Doc) -> String { + let mut str = String::new(); + for i in doc.start..doc.end { + str.push(doc.data[i] as char); + } + str + } + } + fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region { + // Note: regions types embed local node ids. In principle, we + // should translate these node ids into the new decode + // context. However, we do not bother, because region types + // are not used during trans. This also applies to read_ty. + return self.read_ty_encoded(dcx, |decoder| decoder.parse_region()); + } + fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> { + return self.read_ty_encoded(dcx, |decoder| decoder.parse_ty()); + } + + fn read_tys<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> Vec> { + self.read_to_vec(|this| Ok(this.read_ty(dcx))).unwrap().into_iter().collect() + } + + fn read_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::TraitRef<'tcx> { + self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref()) + } + + fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::PolyTraitRef<'tcx> { + ty::Binder(self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref())) + } + + fn read_predicate<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::Predicate<'tcx> + { + self.read_ty_encoded(dcx, |decoder| decoder.parse_predicate()) + } + + fn read_existential_bounds<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::ExistentialBounds<'tcx> + { + self.read_ty_encoded(dcx, |decoder| decoder.parse_existential_bounds()) + } + + fn read_substs<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> subst::Substs<'tcx> { + self.read_opaque(|this, doc| { + Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc, + &mut |a| this.convert_def_id(dcx, a)) + .parse_substs()) + }).unwrap() + } + fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture { + self.read_enum("UpvarCapture", |this| { + let variants = ["ByValue", "ByRef"]; + this.read_enum_variant(&variants, |this, i| { + Ok(match i { + 1 => ty::UpvarCapture::ByValue, + 2 => ty::UpvarCapture::ByRef(ty::UpvarBorrow { + kind: this.read_enum_variant_arg(0, + |this| Decodable::decode(this)).unwrap(), + region: this.read_enum_variant_arg(1, + |this| Ok(this.read_region(dcx))).unwrap() + }), + _ => panic!("bad enum variant for ty::UpvarCapture") + }) + }) + }).unwrap() + } + fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> adjustment::AutoAdjustment<'tcx> { + self.read_enum("AutoAdjustment", |this| { + let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"]; + this.read_enum_variant(&variants, |this, i| { + Ok(match i { + 1 => adjustment::AdjustReifyFnPointer, + 2 => adjustment::AdjustUnsafeFnPointer, + 3 => { + let auto_deref_ref: adjustment::AutoDerefRef = + this.read_enum_variant_arg(0, + |this| Ok(this.read_auto_deref_ref(dcx))).unwrap(); + + adjustment::AdjustDerefRef(auto_deref_ref) + } + _ => panic!("bad enum variant for adjustment::AutoAdjustment") + }) + }) + }).unwrap() + } + + fn read_auto_deref_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> adjustment::AutoDerefRef<'tcx> { + self.read_struct("AutoDerefRef", 2, |this| { + Ok(adjustment::AutoDerefRef { + autoderefs: this.read_struct_field("autoderefs", 0, |this| { + Decodable::decode(this) + }).unwrap(), + autoref: this.read_struct_field("autoref", 1, |this| { + this.read_option(|this, b| { + if b { + Ok(Some(this.read_autoref(dcx))) + } else { + Ok(None) + } + }) + }).unwrap(), + unsize: this.read_struct_field("unsize", 2, |this| { + this.read_option(|this, b| { + if b { + Ok(Some(this.read_ty(dcx))) + } else { + Ok(None) + } + }) + }).unwrap(), + }) + }).unwrap() + } + + fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> adjustment::AutoRef<'tcx> { + self.read_enum("AutoRef", |this| { + let variants = ["AutoPtr", "AutoUnsafe"]; + this.read_enum_variant(&variants, |this, i| { + Ok(match i { + 0 => { + let r: ty::Region = + this.read_enum_variant_arg(0, |this| { + Ok(this.read_region(dcx)) + }).unwrap(); + let m: hir::Mutability = + this.read_enum_variant_arg(1, |this| { + Decodable::decode(this) + }).unwrap(); + + adjustment::AutoPtr(dcx.tcx.mk_region(r), m) + } + 1 => { + let m: hir::Mutability = + this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); + + adjustment::AutoUnsafe(m) + } + _ => panic!("bad enum variant for adjustment::AutoRef") + }) + }) + }).unwrap() + } + + fn read_cast_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>) + -> cast::CastKind + { + Decodable::decode(self).unwrap() + } + + /// Converts a def-id that appears in a type. The correct + /// translation will depend on what kind of def-id this is. + /// This is a subtle point: type definitions are not + /// inlined into the current crate, so if the def-id names + /// a nominal type or type alias, then it should be + /// translated to refer to the source crate. + /// + /// However, *type parameters* are cloned along with the function + /// they are attached to. So we should translate those def-ids + /// to refer to the new, cloned copy of the type parameter. + /// We only see references to free type parameters in the body of + /// an inlined function. In such cases, we need the def-id to + /// be a local id so that the TypeContents code is able to lookup + /// the relevant info in the ty_param_defs table. + /// + /// *Region parameters*, unfortunately, are another kettle of fish. + /// In such cases, def_id's can appear in types to distinguish + /// shadowed bound regions and so forth. It doesn't actually + /// matter so much what we do to these, since regions are erased + /// at trans time, but it's good to keep them consistent just in + /// case. We translate them with `tr_def_id()` which will map + /// the crate numbers back to the original source crate. + /// + /// Scopes will end up as being totally bogus. This can actually + /// be fixed though. + /// + /// Unboxed closures are cloned along with the function being + /// inlined, and all side tables use interned node IDs, so we + /// translate their def IDs accordingly. + /// + /// It'd be really nice to refactor the type repr to not include + /// def-ids so that all these distinctions were unnecessary. + fn convert_def_id(&mut self, + dcx: &DecodeContext, + did: DefId) + -> DefId { + let r = dcx.tr_def_id(did); + debug!("convert_def_id(did={:?})={:?}", did, r); + return r; + } +} + +fn decode_side_tables(dcx: &DecodeContext, + ast_doc: rbml::Doc) { + let tbl_doc = ast_doc.get(c::tag_table as usize); + for (tag, entry_doc) in reader::docs(tbl_doc) { + let mut entry_dsr = reader::Decoder::new(entry_doc); + let id0: ast::NodeId = Decodable::decode(&mut entry_dsr).unwrap(); + let id = dcx.tr_id(id0); + + debug!(">> Side table document with tag 0x{:x} \ + found for id {} (orig {})", + tag, id, id0); + let tag = tag as u32; + let decoded_tag: Option = c::astencode_tag::from_u32(tag); + match decoded_tag { + None => { + dcx.tcx.sess.bug( + &format!("unknown tag found in side tables: {:x}", + tag)); + } + Some(value) => { + let val_dsr = &mut entry_dsr; + + match value { + c::tag_table_def => { + let def = decode_def(dcx, val_dsr); + dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution { + base_def: def, + // This doesn't matter cross-crate. + last_private: LastMod(AllPublic), + depth: 0 + }); + } + c::tag_table_node_type => { + let ty = val_dsr.read_ty(dcx); + debug!("inserting ty for node {}: {:?}", + id, ty); + dcx.tcx.node_type_insert(id, ty); + } + c::tag_table_item_subst => { + let item_substs = ty::ItemSubsts { + substs: val_dsr.read_substs(dcx) + }; + dcx.tcx.tables.borrow_mut().item_substs.insert( + id, item_substs); + } + c::tag_table_freevars => { + let fv_info = val_dsr.read_to_vec(|val_dsr| { + Ok(val_dsr.read_freevar_entry(dcx)) + }).unwrap().into_iter().collect(); + dcx.tcx.freevars.borrow_mut().insert(id, fv_info); + } + c::tag_table_upvar_capture_map => { + let var_id: ast::NodeId = Decodable::decode(val_dsr).unwrap(); + let upvar_id = ty::UpvarId { + var_id: dcx.tr_id(var_id), + closure_expr_id: id + }; + let ub = val_dsr.read_upvar_capture(dcx); + dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); + } + c::tag_table_method_map => { + let (autoderef, method) = val_dsr.read_method_callee(dcx); + let method_call = ty::MethodCall { + expr_id: id, + autoderef: autoderef + }; + dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method); + } + c::tag_table_adjustments => { + let adj = + val_dsr.read_auto_adjustment(dcx); + dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); + } + c::tag_table_cast_kinds => { + let cast_kind = + val_dsr.read_cast_kind(dcx); + dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind); + } + c::tag_table_const_qualif => { + let qualif: ConstQualif = Decodable::decode(val_dsr).unwrap(); + dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif); + } + _ => { + dcx.tcx.sess.bug( + &format!("unknown tag found in side tables: {:x}", + tag)); + } + } + } + } + + debug!(">< Side table doc loaded"); + } +} + +// copy the tcache entries from the original item to the new +// inlined item +fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) { + fn copy_item_type(dcx: &DecodeContext, + inlined_id: ast::NodeId, + remote_did: DefId) { + let inlined_did = dcx.tcx.map.local_def_id(inlined_id); + dcx.tcx.register_item_type(inlined_did, + dcx.tcx.lookup_item_type(remote_did)); + + } + // copy the entry for the item itself + let item_node_id = match ii { + &InlinedItem::Item(ref i) => i.id, + &InlinedItem::TraitItem(_, ref ti) => ti.id, + &InlinedItem::ImplItem(_, ref ii) => ii.id, + &InlinedItem::Foreign(ref fi) => fi.id + }; + copy_item_type(dcx, item_node_id, orig_did); + + // copy the entries of inner items + if let &InlinedItem::Item(ref item) = ii { + match item.node { + hir::ItemEnum(ref def, _) => { + let orig_def = dcx.tcx.lookup_adt_def(orig_did); + for (i_variant, orig_variant) in + def.variants.iter().zip(orig_def.variants.iter()) + { + debug!("astencode: copying variant {:?} => {:?}", + orig_variant.did, i_variant.node.data.id()); + copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did); + } + } + hir::ItemStruct(ref def, _) => { + if !def.is_struct() { + let ctor_did = dcx.tcx.lookup_adt_def(orig_did) + .struct_variant().did; + debug!("astencode: copying ctor {:?} => {:?}", ctor_did, + def.id()); + copy_item_type(dcx, def.id(), ctor_did); + } + } + _ => {} + } + } +} + +fn inlined_item_id_range(v: &InlinedItem) -> ast_util::IdRange { + let mut visitor = ast_util::IdRangeComputingVisitor::new(); + v.visit_ids(&mut visitor); + visitor.result() +} + +// ______________________________________________________________________ +// Testing of astencode_gen + +#[cfg(test)] +fn encode_item_ast(rbml_w: &mut Encoder, item: &hir::Item) { + rbml_w.start_tag(c::tag_tree as usize); + (*item).encode(rbml_w); + rbml_w.end_tag(); +} + +#[cfg(test)] +fn decode_item_ast(par_doc: rbml::Doc) -> hir::Item { + let chi_doc = par_doc.get(c::tag_tree as usize); + let mut d = reader::Decoder::new(chi_doc); + Decodable::decode(&mut d).unwrap() +} + +#[cfg(test)] +trait FakeExtCtxt { + fn call_site(&self) -> codemap::Span; + fn cfg(&self) -> ast::CrateConfig; + fn ident_of(&self, st: &str) -> ast::Ident; + fn name_of(&self, st: &str) -> ast::Name; + fn parse_sess(&self) -> &parse::ParseSess; +} + +#[cfg(test)] +impl FakeExtCtxt for parse::ParseSess { + fn call_site(&self) -> codemap::Span { + codemap::Span { + lo: codemap::BytePos(0), + hi: codemap::BytePos(0), + expn_id: codemap::NO_EXPANSION, + } + } + fn cfg(&self) -> ast::CrateConfig { Vec::new() } + fn ident_of(&self, st: &str) -> ast::Ident { + parse::token::str_to_ident(st) + } + fn name_of(&self, st: &str) -> ast::Name { + parse::token::intern(st) + } + fn parse_sess(&self) -> &parse::ParseSess { self } +} + +#[cfg(test)] +struct FakeNodeIdAssigner; + +#[cfg(test)] +// It should go without saying that this may give unexpected results. Avoid +// lowering anything which needs new nodes. +impl NodeIdAssigner for FakeNodeIdAssigner { + fn next_node_id(&self) -> NodeId { + 0 + } + + fn peek_node_id(&self) -> NodeId { + 0 + } +} + +#[cfg(test)] +fn mk_ctxt() -> parse::ParseSess { + parse::ParseSess::new() +} + +#[cfg(test)] +fn roundtrip(in_item: hir::Item) { + let mut wr = Cursor::new(Vec::new()); + encode_item_ast(&mut Encoder::new(&mut wr), &in_item); + let rbml_doc = rbml::Doc::new(wr.get_ref()); + let out_item = decode_item_ast(rbml_doc); + + assert!(in_item == out_item); +} + +#[test] +fn test_basic() { + let cx = mk_ctxt(); + let fnia = FakeNodeIdAssigner; + let lcx = LoweringContext::new(&fnia, None); + roundtrip(lower_item(&lcx, "e_item!(&cx, + fn foo() {} + ).unwrap())); +} + +#[test] +fn test_smalltalk() { + let cx = mk_ctxt(); + let fnia = FakeNodeIdAssigner; + let lcx = LoweringContext::new(&fnia, None); + roundtrip(lower_item(&lcx, "e_item!(&cx, + fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed. + ).unwrap())); +} + +#[test] +fn test_more() { + let cx = mk_ctxt(); + let fnia = FakeNodeIdAssigner; + let lcx = LoweringContext::new(&fnia, None); + roundtrip(lower_item(&lcx, "e_item!(&cx, + fn foo(x: usize, y: usize) -> usize { + let z = x + y; + return z; + } + ).unwrap())); +} + +#[test] +fn test_simplification() { + let cx = mk_ctxt(); + let item = quote_item!(&cx, + fn new_int_alist() -> alist { + fn eq_int(a: isize, b: isize) -> bool { a == b } + return alist {eq_fn: eq_int, data: Vec::new()}; + } + ).unwrap(); + let fnia = FakeNodeIdAssigner; + let lcx = LoweringContext::new(&fnia, None); + let hir_item = lower_item(&lcx, &item); + let item_in = InlinedItemRef::Item(&hir_item); + let item_out = simplify_ast(item_in); + let item_exp = InlinedItem::Item(P(lower_item(&lcx, "e_item!(&cx, + fn new_int_alist() -> alist { + return alist {eq_fn: eq_int, data: Vec::new()}; + } + ).unwrap()))); + match (item_out, item_exp) { + (InlinedItem::Item(item_out), InlinedItem::Item(item_exp)) => { + assert!(pprust::item_to_string(&*item_out) == + pprust::item_to_string(&*item_exp)); + } + _ => panic!() + } +} diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs new file mode 100644 index 00000000000..b6454a4c81a --- /dev/null +++ b/src/librustc_metadata/common.rs @@ -0,0 +1,245 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types, non_upper_case_globals)] + +pub use self::astencode_tag::*; + +// RBML enum definitions and utils shared by the encoder and decoder +// +// 0x00..0x1f: reserved for RBML generic type tags +// 0x20..0xef: free for use, preferred for frequent tags +// 0xf0..0xff: internally used by RBML to encode 0x100..0xfff in two bytes +// 0x100..0xfff: free for use, preferred for infrequent tags + +pub const tag_items: usize = 0x100; // top-level only + +pub const tag_paths_data_name: usize = 0x20; + +pub const tag_def_id: usize = 0x21; + +pub const tag_items_data: usize = 0x22; + +pub const tag_items_data_item: usize = 0x23; + +pub const tag_items_data_item_family: usize = 0x24; + +pub const tag_items_data_item_type: usize = 0x25; + +pub const tag_items_data_item_symbol: usize = 0x26; + +pub const tag_items_data_item_variant: usize = 0x27; + +pub const tag_items_data_parent_item: usize = 0x28; + +pub const tag_items_data_item_is_tuple_struct_ctor: usize = 0x29; + +pub const tag_items_closure_kind: usize = 0x2a; +pub const tag_items_closure_ty: usize = 0x2b; +pub const tag_def_key: usize = 0x2c; + +// GAP 0x2d 0x2e + +pub const tag_index: usize = 0x110; // top-level only +pub const tag_xref_index: usize = 0x111; // top-level only +pub const tag_xref_data: usize = 0x112; // top-level only + +pub const tag_meta_item_name_value: usize = 0x2f; + +pub const tag_meta_item_name: usize = 0x30; + +pub const tag_meta_item_value: usize = 0x31; + +pub const tag_attributes: usize = 0x101; // top-level only + +pub const tag_attribute: usize = 0x32; + +pub const tag_meta_item_word: usize = 0x33; + +pub const tag_meta_item_list: usize = 0x34; + +// The list of crates that this crate depends on +pub const tag_crate_deps: usize = 0x102; // top-level only + +// A single crate dependency +pub const tag_crate_dep: usize = 0x35; + +pub const tag_crate_hash: usize = 0x103; // top-level only +pub const tag_crate_crate_name: usize = 0x104; // top-level only + +pub const tag_crate_dep_crate_name: usize = 0x36; +pub const tag_crate_dep_hash: usize = 0x37; +pub const tag_crate_dep_explicitly_linked: usize = 0x38; // top-level only + +pub const tag_item_trait_item: usize = 0x3a; + +pub const tag_item_trait_ref: usize = 0x3b; + +// discriminator value for variants +pub const tag_disr_val: usize = 0x3c; + +// used to encode ast_map::PathElem +pub const tag_path: usize = 0x3d; +pub const tag_path_len: usize = 0x3e; +pub const tag_path_elem_mod: usize = 0x3f; +pub const tag_path_elem_name: usize = 0x40; +pub const tag_item_field: usize = 0x41; + +pub const tag_item_variances: usize = 0x43; +/* + trait items contain tag_item_trait_item elements, + impl items contain tag_item_impl_item elements, and classes + have both. That's because some code treats classes like traits, + and other code treats them like impls. Because classes can contain + both, tag_item_trait_item and tag_item_impl_item have to be two + different tags. + */ +pub const tag_item_impl_item: usize = 0x44; +pub const tag_item_trait_method_explicit_self: usize = 0x45; + + +// Reexports are found within module tags. Each reexport contains def_ids +// and names. +pub const tag_items_data_item_reexport: usize = 0x46; +pub const tag_items_data_item_reexport_def_id: usize = 0x47; +pub const tag_items_data_item_reexport_name: usize = 0x48; + +// used to encode crate_ctxt side tables +enum_from_u32! { + #[derive(Copy, Clone, PartialEq)] + #[repr(usize)] + pub enum astencode_tag { // Reserves 0x50 -- 0x6f + tag_ast = 0x50, + + tag_tree = 0x51, + + // GAP 0x52 + tag_table = 0x53, + // GAP 0x54, 0x55 + tag_table_def = 0x56, + tag_table_node_type = 0x57, + tag_table_item_subst = 0x58, + tag_table_freevars = 0x59, + // GAP 0x5a, 0x5b, 0x5c, 0x5d, 0x5e + tag_table_method_map = 0x5f, + // GAP 0x60 + tag_table_adjustments = 0x61, + // GAP 0x62, 0x63, 0x64, 0x65 + tag_table_upvar_capture_map = 0x66, + // GAP 0x67, 0x68 + tag_table_const_qualif = 0x69, + tag_table_cast_kinds = 0x6a, + } +} + +pub const tag_item_trait_item_sort: usize = 0x70; + +pub const tag_crate_triple: usize = 0x105; // top-level only + +pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only + +// Language items are a top-level directory (for speed). Hierarchy: +// +// tag_lang_items +// - tag_lang_items_item +// - tag_lang_items_item_id: u32 +// - tag_lang_items_item_index: u32 + +pub const tag_lang_items: usize = 0x107; // top-level only +pub const tag_lang_items_item: usize = 0x73; +pub const tag_lang_items_item_id: usize = 0x74; +pub const tag_lang_items_item_index: usize = 0x75; +pub const tag_lang_items_missing: usize = 0x76; + +pub const tag_item_unnamed_field: usize = 0x77; +pub const tag_items_data_item_visibility: usize = 0x78; +pub const tag_items_data_item_inherent_impl: usize = 0x79; +// GAP 0x7a +pub const tag_mod_child: usize = 0x7b; +pub const tag_misc_info: usize = 0x108; // top-level only +pub const tag_misc_info_crate_items: usize = 0x7c; + +pub const tag_impls: usize = 0x109; // top-level only +pub const tag_impls_trait: usize = 0x7d; +pub const tag_impls_trait_impl: usize = 0x7e; + +// GAP 0x7f, 0x80, 0x81 + +pub const tag_native_libraries: usize = 0x10a; // top-level only +pub const tag_native_libraries_lib: usize = 0x82; +pub const tag_native_libraries_name: usize = 0x83; +pub const tag_native_libraries_kind: usize = 0x84; + +pub const tag_plugin_registrar_fn: usize = 0x10b; // top-level only + +pub const tag_method_argument_names: usize = 0x85; +pub const tag_method_argument_name: usize = 0x86; + +pub const tag_reachable_ids: usize = 0x10c; // top-level only +pub const tag_reachable_id: usize = 0x87; + +pub const tag_items_data_item_stability: usize = 0x88; + +pub const tag_items_data_item_repr: usize = 0x89; + +pub const tag_struct_fields: usize = 0x10d; // top-level only +pub const tag_struct_field: usize = 0x8a; + +pub const tag_items_data_item_struct_ctor: usize = 0x8b; +pub const tag_attribute_is_sugared_doc: usize = 0x8c; +// GAP 0x8d +pub const tag_items_data_region: usize = 0x8e; + +pub const tag_region_param_def: usize = 0x8f; +pub const tag_region_param_def_ident: usize = 0x90; +pub const tag_region_param_def_def_id: usize = 0x91; +pub const tag_region_param_def_space: usize = 0x92; +pub const tag_region_param_def_index: usize = 0x93; + +pub const tag_type_param_def: usize = 0x94; + +pub const tag_item_generics: usize = 0x95; +pub const tag_method_ty_generics: usize = 0x96; + +pub const tag_type_predicate: usize = 0x97; +pub const tag_self_predicate: usize = 0x98; +pub const tag_fn_predicate: usize = 0x99; + +pub const tag_unsafety: usize = 0x9a; + +pub const tag_associated_type_names: usize = 0x9b; +pub const tag_associated_type_name: usize = 0x9c; + +pub const tag_polarity: usize = 0x9d; + +pub const tag_macro_defs: usize = 0x10e; // top-level only +pub const tag_macro_def: usize = 0x9e; +pub const tag_macro_def_body: usize = 0x9f; + +pub const tag_paren_sugar: usize = 0xa0; + +pub const tag_codemap: usize = 0xa1; +pub const tag_codemap_filemap: usize = 0xa2; + +pub const tag_item_super_predicates: usize = 0xa3; + +pub const tag_defaulted_trait: usize = 0xa4; + +pub const tag_impl_coerce_unsized_kind: usize = 0xa5; + +pub const tag_items_data_item_constness: usize = 0xa6; + +pub const tag_rustc_version: usize = 0x10f; +pub fn rustc_version() -> String { + format!( + "rustc {}", + option_env!("CFG_VERSION").unwrap_or("unknown version") + ) +} diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs new file mode 100644 index 00000000000..89aa3bf8661 --- /dev/null +++ b/src/librustc_metadata/creader.rs @@ -0,0 +1,963 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] + +//! Validates all used crates and extern libraries and loads their metadata + +use common::rustc_version; +use cstore::{self, CStore, CrateSource, MetadataBlob}; +use decoder; +use loader::{self, CratePaths}; + +use rustc::back::svh::Svh; +use rustc::session::{config, Session}; +use rustc::session::search_paths::PathKind; +use rustc::middle::cstore::validate_crate_name; +use rustc::util::nodemap::FnvHashMap; +use rustc::front::map as hir_map; + +use std::cell::{RefCell, Cell}; +use std::path::PathBuf; +use std::rc::Rc; +use std::fs; + +use syntax::ast; +use syntax::abi; +use syntax::codemap::{self, Span, mk_sp, Pos}; +use syntax::parse; +use syntax::attr; +use syntax::attr::AttrMetaMethods; +use syntax::parse::token::InternedString; +use syntax::util::small_vector::SmallVector; +use rustc_front::intravisit::Visitor; +use rustc_front::hir; +use log; + +pub struct LocalCrateReader<'a, 'b:'a> { + sess: &'a Session, + cstore: &'a CStore, + creader: CrateReader<'a>, + ast_map: &'a hir_map::Map<'b>, +} + +pub struct CrateReader<'a> { + sess: &'a Session, + cstore: &'a CStore, + next_crate_num: ast::CrateNum, + foreign_item_map: FnvHashMap>, +} + +impl<'a, 'b, 'hir> Visitor<'hir> for LocalCrateReader<'a, 'b> { + fn visit_item(&mut self, a: &'hir hir::Item) { + self.process_item(a); + } +} + +fn dump_crates(cstore: &CStore) { + info!("resolved crates:"); + cstore.iter_crate_data_origins(|_, data, opt_source| { + info!(" name: {}", data.name()); + info!(" cnum: {}", data.cnum); + info!(" hash: {}", data.hash()); + info!(" reqd: {}", data.explicitly_linked.get()); + opt_source.map(|cs| { + let CrateSource { dylib, rlib, cnum: _ } = cs; + dylib.map(|dl| info!(" dylib: {}", dl.0.display())); + rlib.map(|rl| info!(" rlib: {}", rl.0.display())); + }); + }) +} + +fn should_link(i: &ast::Item) -> bool { + !attr::contains_name(&i.attrs, "no_link") +} +// Dup for the hir +fn should_link_hir(i: &hir::Item) -> bool { + !attr::contains_name(&i.attrs, "no_link") +} + +struct CrateInfo { + ident: String, + name: String, + id: ast::NodeId, + should_link: bool, +} + +fn register_native_lib(sess: &Session, + cstore: &CStore, + span: Option, + name: String, + kind: cstore::NativeLibraryKind) { + if name.is_empty() { + match span { + Some(span) => { + span_err!(sess, span, E0454, + "#[link(name = \"\")] given with empty name"); + } + None => { + sess.err("empty library name given via `-l`"); + } + } + return + } + let is_osx = sess.target.target.options.is_like_osx; + if kind == cstore::NativeFramework && !is_osx { + let msg = "native frameworks are only available on OSX targets"; + match span { + Some(span) => { + span_err!(sess, span, E0455, + "{}", msg) + } + None => sess.err(msg), + } + } + cstore.add_used_library(name, kind); +} + +// Extra info about a crate loaded for plugins or exported macros. +struct ExtensionCrate { + metadata: PMDSource, + dylib: Option, + target_only: bool, +} + +enum PMDSource { + Registered(Rc), + 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(), + } + } +} + +impl<'a> CrateReader<'a> { + pub fn new(sess: &'a Session, cstore: &'a CStore) -> CrateReader<'a> { + CrateReader { + sess: sess, + cstore: cstore, + next_crate_num: cstore.next_crate_num(), + foreign_item_map: FnvHashMap(), + } + } + + fn extract_crate_info(&self, i: &ast::Item) -> Option { + match i.node { + ast::ItemExternCrate(ref path_opt) => { + debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", + i.ident, path_opt); + let name = match *path_opt { + Some(name) => { + validate_crate_name(Some(self.sess), &name.as_str(), + Some(i.span)); + name.to_string() + } + None => i.ident.to_string(), + }; + Some(CrateInfo { + ident: i.ident.to_string(), + name: name, + id: i.id, + should_link: should_link(i), + }) + } + _ => None + } + } + + // Dup of the above, but for the hir + fn extract_crate_info_hir(&self, i: &hir::Item) -> Option { + match i.node { + hir::ItemExternCrate(ref path_opt) => { + debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", + i.name, path_opt); + let name = match *path_opt { + Some(name) => { + validate_crate_name(Some(self.sess), &name.as_str(), + Some(i.span)); + name.to_string() + } + None => i.name.to_string(), + }; + Some(CrateInfo { + ident: i.name.to_string(), + name: name, + id: i.id, + should_link: should_link_hir(i), + }) + } + _ => None + } + } + + fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind) + -> Option { + let mut ret = None; + self.cstore.iter_crate_data(|cnum, data| { + if data.name != name { return } + + match hash { + Some(hash) if *hash == data.hash() => { ret = Some(cnum); return } + Some(..) => return, + None => {} + } + + // 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. + // + // 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.cstore.do_get_used_crate_source(cnum).unwrap(); + if let Some(locs) = self.sess.opts.externs.get(name) { + let found = locs.iter().any(|l| { + let l = fs::canonicalize(l).ok(); + 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); + } + return + } + + // 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); + } + }); + return ret; + } + + 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(); + } + } + + fn register_crate(&mut self, + root: &Option, + ident: &str, + name: &str, + span: Span, + lib: loader::Library, + explicitly_linked: bool) + -> (ast::CrateNum, Rc, + cstore::CrateSource) { + self.verify_rustc_version(name, span, &lib.metadata); + + // 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(), + dylib: lib.dylib.clone().map(|p| p.0), + rlib: lib.rlib.clone().map(|p| p.0), + }) + } else { + None + }; + // Maintain a reference to the top most crate. + let root = if root.is_some() { root } else { &crate_paths }; + + let loader::Library { dylib, rlib, metadata } = lib; + + let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span); + let staged_api = self.is_staged_api(metadata.as_slice()); + + let cmeta = Rc::new(cstore::crate_metadata { + name: name.to_string(), + local_path: RefCell::new(SmallVector::zero()), + local_def_path: RefCell::new(vec![]), + index: decoder::load_index(metadata.as_slice()), + xref_index: decoder::load_xrefs(metadata.as_slice()), + data: metadata, + cnum_map: RefCell::new(cnum_map), + cnum: cnum, + codemap_import_info: RefCell::new(vec![]), + span: span, + staged_api: staged_api, + explicitly_linked: Cell::new(explicitly_linked), + }); + + let source = cstore::CrateSource { + dylib: dylib, + rlib: rlib, + cnum: cnum, + }; + + self.cstore.set_crate_data(cnum, cmeta.clone()); + self.cstore.add_used_crate_source(source.clone()); + (cnum, cmeta, source) + } + + fn is_staged_api(&self, data: &[u8]) -> bool { + let attrs = decoder::get_crate_attributes(data); + for attr in &attrs { + if attr.name() == "stable" || attr.name() == "unstable" { + return true + } + } + false + } + + fn resolve_crate(&mut self, + root: &Option, + ident: &str, + name: &str, + hash: Option<&Svh>, + span: Span, + kind: PathKind, + explicitly_linked: bool) + -> (ast::CrateNum, Rc, + cstore::CrateSource) { + enum LookupResult { + Previous(ast::CrateNum), + Loaded(loader::Library), + } + let result = match self.existing_match(name, hash, kind) { + Some(cnum) => LookupResult::Previous(cnum), + 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), + target: &self.sess.target.target, + triple: &self.sess.opts.target_triple, + root: root, + rejected_via_hash: vec!(), + rejected_via_triple: vec!(), + rejected_via_kind: vec!(), + should_match_name: true, + }; + let library = load_ctxt.load_library_crate(); + + // In the case that we're loading a crate, but not matching + // against a hash, we could load a crate which has the same hash + // as an already loaded crate. If this is the case prevent + // duplicates by just using the first crate. + let meta_hash = decoder::get_crate_hash(library.metadata + .as_slice()); + let mut result = LookupResult::Loaded(library); + self.cstore.iter_crate_data(|cnum, data| { + if data.name() == name && meta_hash == data.hash() { + assert!(hash.is_none()); + result = LookupResult::Previous(cnum); + } + }); + result + } + }; + + match result { + LookupResult::Previous(cnum) => { + let data = self.cstore.get_crate_data(cnum); + if explicitly_linked && !data.explicitly_linked.get() { + data.explicitly_linked.set(explicitly_linked); + } + (cnum, data, self.cstore.do_get_used_crate_source(cnum).unwrap()) + } + LookupResult::Loaded(library) => { + self.register_crate(root, ident, name, span, library, + explicitly_linked) + } + } + } + + // Go through the crate metadata and load any crates that it references + fn resolve_crate_deps(&mut self, + root: &Option, + 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, + &dep.name, + &dep.name, + Some(&dep.hash), + span, + PathKind::Dependency, + dep.explicitly_linked); + (dep.cnum, local_cnum) + }).collect() + } + + fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { + let target_triple = &self.sess.opts.target_triple[..]; + let is_cross = target_triple != config::host_triple(); + let mut should_link = info.should_link && !is_cross; + let mut target_only = false; + let ident = info.ident.clone(); + let name = info.name.clone(); + let mut load_ctxt = loader::Context { + sess: self.sess, + span: span, + ident: &ident[..], + crate_name: &name[..], + hash: None, + filesearch: self.sess.host_filesearch(PathKind::Crate), + target: &self.sess.host, + triple: config::host_triple(), + root: &None, + rejected_via_hash: vec!(), + rejected_via_triple: vec!(), + rejected_via_kind: vec!(), + should_match_name: true, + }; + let library = match load_ctxt.maybe_load_library_crate() { + Some(l) => l, + None if is_cross => { + // Try loading from target crates. This will abort later if we + // try to load a plugin registrar function, + target_only = true; + should_link = info.should_link; + + load_ctxt.target = &self.sess.target.target; + load_ctxt.triple = target_triple; + load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate); + load_ctxt.load_library_crate() + } + None => { load_ctxt.report_load_errs(); unreachable!() }, + }; + + let dylib = library.dylib.clone(); + let register = should_link && self.existing_match(&info.name, + None, + PathKind::Crate).is_none(); + let metadata = if register { + // Register crate now to avoid double-reading metadata + let (_, cmd, _) = self.register_crate(&None, &info.ident, + &info.name, span, library, + true); + PMDSource::Registered(cmd) + } else { + // Not registering the crate; just hold on to the metadata + PMDSource::Owned(library.metadata) + }; + + ExtensionCrate { + metadata: metadata, + dylib: dylib.map(|p| p.0), + target_only: target_only, + } + } + + /// Read exported macros. + pub fn read_exported_macros(&mut self, item: &ast::Item) -> Vec { + let ci = self.extract_crate_info(item).unwrap(); + let ekrate = self.read_extension_crate(item.span, &ci); + + let source_name = format!("<{} macros>", item.ident); + let mut macros = vec![]; + decoder::each_exported_macro(ekrate.metadata.as_slice(), + &*self.cstore.intr, + |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; + let body = match p.parse_all_token_trees() { + Ok(body) => body, + Err(err) => panic!(err), + }; + let span = mk_sp(lo, p.last_span.hi); + p.abort_if_errors(); + + // Mark the attrs as used + for attr in &attrs { + attr::mark_used(attr); + } + + macros.push(ast::MacroDef { + ident: ast::Ident::with_empty_ctxt(name), + attrs: attrs, + id: ast::DUMMY_NODE_ID, + span: span, + imported_from: Some(item.ident), + // overridden in plugin/load.rs + export: false, + use_locally: false, + allow_internal_unstable: false, + + body: body, + }); + true + } + ); + macros + } + + /// Look for a plugin registrar. Returns library path and symbol name. + pub fn find_plugin_registrar(&mut self, span: Span, name: &str) + -> Option<(PathBuf, String)> { + 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 { + // Need to abort before syntax expansion. + let message = format!("plugin `{}` is not available for triple `{}` \ + (only found {})", + name, + config::host_triple(), + self.sess.opts.target_triple); + span_err!(self.sess, span, E0456, "{}", &message[..]); + self.sess.abort_if_errors(); + } + + let registrar = + decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()) + .map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id)); + + match (ekrate.dylib.as_ref(), registrar) { + (Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)), + (None, Some(_)) => { + span_err!(self.sess, span, E0457, + "plugin `{}` only found in rlib format, but must be available \ + in dylib format", + name); + // No need to abort because the loading code will just ignore this + // empty dylib. + None + } + _ => None, + } + } + + fn register_statically_included_foreign_items(&mut self) { + let libs = self.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.cstore.add_statically_included_foreign_item(*id); + } + } + } + } + + 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.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.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.cstore.get_crate_data(krate); + if data.needs_allocator() { + let krate_name = data.name(); + let data = me.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); + } + } + } +} + +impl<'a, 'b> LocalCrateReader<'a, 'b> { + pub fn new(sess: &'a Session, cstore: &'a CStore, map: &'a hir_map::Map<'b>) -> LocalCrateReader<'a, 'b> { + LocalCrateReader { + sess: sess, + cstore: cstore, + creader: CrateReader::new(sess, cstore), + 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: &hir::Crate) { + self.process_crate(krate); + krate.visit_all_items(self); + self.creader.inject_allocator_crate(); + + if log_enabled!(log::INFO) { + dump_crates(&self.cstore); + } + + for &(ref name, kind) in &self.sess.opts.libs { + register_native_lib(self.sess, self.cstore, None, name.clone(), kind); + } + self.creader.register_statically_included_foreign_items(); + } + + fn process_crate(&self, c: &hir::Crate) { + for a in c.attrs.iter().filter(|m| m.name() == "link_args") { + match a.value_str() { + Some(ref linkarg) => self.cstore.add_used_link_args(&linkarg), + None => { /* fallthrough */ } + } + } + } + + fn process_item(&mut self, i: &hir::Item) { + match i.node { + hir::ItemExternCrate(_) => { + if !should_link_hir(i) { + return; + } + + match self.creader.extract_crate_info_hir(i) { + Some(info) => { + let (cnum, cmeta, _) = self.creader.resolve_crate(&None, + &info.ident, + &info.name, + None, + i.span, + PathKind::Crate, + true); + 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); + self.ast_map.with_path(i.id, |path| { + cmeta.update_local_path(path) + }); + self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); + } + None => () + } + } + hir::ItemForeignMod(ref fm) => self.process_foreign_mod(i, fm), + _ => { } + } + } + + fn process_foreign_mod(&mut self, i: &hir::Item, fm: &hir::ForeignMod) { + if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic || fm.abi == abi::PlatformIntrinsic { + return; + } + + // 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.cstore.add_used_link_args(&linkarg); + } + } + + // 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) => { + span_err!(self.sess, m.span, E0458, + "unknown kind: `{}`", k); + 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 => { + span_err!(self.sess, m.span, E0459, + "#[link(...)] specified without `name = \"foo\"`"); + InternedString::new("foo") + } + }; + register_native_lib(self.sess, self.cstore, 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)); + } + } +} + +/// 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. +pub fn import_codemap(local_codemap: &codemap::CodeMap, + metadata: &MetadataBlob) + -> Vec { + 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. + 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; + } + + 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 + } +} diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs new file mode 100644 index 00000000000..99fa18837eb --- /dev/null +++ b/src/librustc_metadata/csearch.rs @@ -0,0 +1,487 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use astencode; +use cstore; +use decoder; +use encoder; +use loader; + +use middle::cstore::{CrateStore, CrateSource, ChildItem, FoundAst}; +use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; +use middle::def; +use middle::lang_items; +use middle::ty::{self, Ty}; +use middle::def_id::{DefId, DefIndex}; + +use rustc::front::map as ast_map; +use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; + +use std::cell::RefCell; +use std::rc::Rc; +use std::path::PathBuf; +use syntax::ast; +use syntax::attr; +use rustc_back::svh::Svh; +use rustc_back::target::Target; +use rustc_front::hir; + +impl<'tcx> CrateStore<'tcx> for cstore::CStore { + fn stability(&self, def: DefId) -> Option + { + let cdata = self.get_crate_data(def.krate); + decoder::get_stability(&*cdata, def.index) + } + + fn closure_kind(&self, _tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind + { + assert!(!def_id.is_local()); + let cdata = self.get_crate_data(def_id.krate); + decoder::closure_kind(&*cdata, def_id.index) + } + + fn closure_ty(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> + { + assert!(!def_id.is_local()); + let cdata = self.get_crate_data(def_id.krate); + decoder::closure_ty(&*cdata, def_id.index, tcx) + } + + fn item_variances(&self, def: DefId) -> ty::ItemVariances { + let cdata = self.get_crate_data(def.krate); + decoder::get_item_variances(&*cdata, def.index) + } + + fn repr_attrs(&self, def: DefId) -> Vec { + let cdata = self.get_crate_data(def.krate); + decoder::get_repr_attrs(&*cdata, def.index) + } + + fn item_type(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> ty::TypeScheme<'tcx> + { + let cdata = self.get_crate_data(def.krate); + decoder::get_type(&*cdata, def.index, tcx) + } + + fn item_predicates(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> ty::GenericPredicates<'tcx> + { + let cdata = self.get_crate_data(def.krate); + decoder::get_predicates(&*cdata, def.index, tcx) + } + + fn item_super_predicates(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> ty::GenericPredicates<'tcx> + { + let cdata = self.get_crate_data(def.krate); + decoder::get_super_predicates(&*cdata, def.index, tcx) + } + + fn item_attrs(&self, def_id: DefId) -> Vec + { + let cdata = self.get_crate_data(def_id.krate); + decoder::get_item_attrs(&*cdata, def_id.index) + } + + fn item_symbol(&self, def: DefId) -> String + { + let cdata = self.get_crate_data(def.krate); + decoder::get_symbol(&cdata, def.index) + } + + fn trait_def(&self, tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::TraitDef<'tcx> + { + let cdata = self.get_crate_data(def.krate); + decoder::get_trait_def(&*cdata, def.index, tcx) + } + + fn adt_def(&self, tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> + { + let cdata = self.get_crate_data(def.krate); + decoder::get_adt_def(&self.intr, &*cdata, def.index, tcx) + } + + fn method_arg_names(&self, did: DefId) -> Vec + { + let cdata = self.get_crate_data(did.krate); + decoder::get_method_arg_names(&cdata, did.index) + } + + fn item_path(&self, def: DefId) -> Vec { + let cdata = self.get_crate_data(def.krate); + let path = decoder::get_item_path(&*cdata, def.index); + + cdata.with_local_path(|cpath| { + let mut r = Vec::with_capacity(cpath.len() + path.len()); + r.push_all(cpath); + r.push_all(&path); + r + }) + } + + fn item_name(&self, def: DefId) -> ast::Name { + let cdata = self.get_crate_data(def.krate); + decoder::get_item_name(&self.intr, &cdata, def.index) + } + + + fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec + { + let mut result = vec![]; + let cdata = self.get_crate_data(def_id.krate); + decoder::each_inherent_implementation_for_type(&*cdata, def_id.index, + |iid| result.push(iid)); + result + } + + fn implementations_of_trait(&self, def_id: DefId) -> Vec + { + let mut result = vec![]; + self.iter_crate_data(|_, cdata| { + decoder::each_implementation_for_trait(cdata, def_id, &mut |iid| { + result.push(iid) + }) + }); + result + } + + fn provided_trait_methods(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Vec>> + { + let cdata = self.get_crate_data(def.krate); + decoder::get_provided_trait_methods(self.intr.clone(), &*cdata, def.index, tcx) + } + + fn trait_item_def_ids(&self, def: DefId) + -> Vec + { + let cdata = self.get_crate_data(def.krate); + decoder::get_trait_item_def_ids(&*cdata, def.index) + } + + fn impl_items(&self, impl_def_id: DefId) -> Vec + { + let cdata = self.get_crate_data(impl_def_id.krate); + decoder::get_impl_items(&*cdata, impl_def_id.index) + } + + fn impl_polarity(&self, def: DefId) -> Option + { + let cdata = self.get_crate_data(def.krate); + decoder::get_impl_polarity(&*cdata, def.index) + } + + fn impl_trait_ref(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Option> + { + let cdata = self.get_crate_data(def.krate); + decoder::get_impl_trait(&*cdata, def.index, tcx) + } + + fn custom_coerce_unsized_kind(&self, def: DefId) + -> Option + { + let cdata = self.get_crate_data(def.krate); + decoder::get_custom_coerce_unsized_kind(&*cdata, def.index) + } + + // FIXME: killme + fn associated_consts(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> Vec>> { + let cdata = self.get_crate_data(def.krate); + decoder::get_associated_consts(self.intr.clone(), &*cdata, def.index, tcx) + } + + fn trait_of_item(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) -> Option + { + let cdata = self.get_crate_data(def_id.krate); + decoder::get_trait_of_item(&*cdata, def_id.index, tcx) + } + + fn impl_or_trait_item(&self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> ty::ImplOrTraitItem<'tcx> + { + let cdata = self.get_crate_data(def.krate); + decoder::get_impl_or_trait_item( + self.intr.clone(), + &*cdata, + def.index, + tcx) + } + + fn is_const_fn(&self, did: DefId) -> bool + { + let cdata = self.get_crate_data(did.krate); + decoder::is_const_fn(&cdata, did.index) + } + + fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool + { + let cdata = self.get_crate_data(trait_def_id.krate); + decoder::is_defaulted_trait(&*cdata, trait_def_id.index) + } + + fn is_impl(&self, did: DefId) -> bool + { + let cdata = self.get_crate_data(did.krate); + decoder::is_impl(&*cdata, did.index) + } + + fn is_default_impl(&self, impl_did: DefId) -> bool { + let cdata = self.get_crate_data(impl_did.krate); + decoder::is_default_impl(&*cdata, impl_did.index) + } + + fn is_extern_fn(&self, tcx: &ty::ctxt<'tcx>, did: DefId) -> bool + { + let cdata = self.get_crate_data(did.krate); + decoder::is_extern_fn(&*cdata, did.index, tcx) + } + + fn is_static(&self, did: DefId) -> bool + { + let cdata = self.get_crate_data(did.krate); + decoder::is_static(&*cdata, did.index) + } + + fn is_static_method(&self, def: DefId) -> bool + { + let cdata = self.get_crate_data(def.krate); + decoder::is_static_method(&*cdata, def.index) + } + + fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool + { + self.do_is_statically_included_foreign_item(id) + } + + fn is_typedef(&self, did: DefId) -> bool { + let cdata = self.get_crate_data(did.krate); + decoder::is_typedef(&*cdata, did.index) + } + + fn dylib_dependency_formats(&self, cnum: ast::CrateNum) + -> Vec<(ast::CrateNum, LinkagePreference)> + { + let cdata = self.get_crate_data(cnum); + decoder::get_dylib_dependency_formats(&cdata) + } + + fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)> + { + let mut result = vec![]; + let crate_data = self.get_crate_data(cnum); + decoder::each_lang_item(&*crate_data, |did, lid| { + result.push((did, lid)); true + }); + result + } + + fn missing_lang_items(&self, cnum: ast::CrateNum) + -> Vec + { + let cdata = self.get_crate_data(cnum); + decoder::get_missing_lang_items(&*cdata) + } + + fn is_staged_api(&self, cnum: ast::CrateNum) -> bool + { + self.get_crate_data(cnum).staged_api + } + + fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool + { + self.get_crate_data(cnum).explicitly_linked.get() + } + + fn is_allocator(&self, cnum: ast::CrateNum) -> bool + { + self.get_crate_data(cnum).is_allocator() + } + + fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec + { + decoder::get_crate_attributes(self.get_crate_data(cnum).data()) + } + + fn crate_name(&self, cnum: ast::CrateNum) -> String + { + self.get_crate_data(cnum).name.clone() + } + + fn crate_hash(&self, cnum: ast::CrateNum) -> Svh + { + let cdata = self.get_crate_data(cnum); + decoder::get_crate_hash(cdata.data()) + } + + fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) + -> FnvHashMap> + { + decoder::get_struct_field_attrs(&*self.get_crate_data(cnum)) + } + + fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option + { + let cdata = self.get_crate_data(cnum); + decoder::get_plugin_registrar_fn(cdata.data()).map(|index| DefId { + krate: cnum, + index: index + }) + } + + fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)> + { + let cdata = self.get_crate_data(cnum); + decoder::get_native_libraries(&*cdata) + } + + fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec + { + let cdata = self.get_crate_data(cnum); + decoder::get_reachable_ids(&*cdata) + } + + fn def_path(&self, def: DefId) -> ast_map::DefPath + { + let cdata = self.get_crate_data(def.krate); + let path = decoder::def_path(&*cdata, def.index); + let local_path = cdata.local_def_path(); + local_path.into_iter().chain(path).collect() + } + + fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option + { + let cdata = self.get_crate_data(did.krate); + decoder::get_tuple_struct_definition_if_ctor(&*cdata, did.index) + } + + fn struct_field_names(&self, def: DefId) -> Vec + { + let cdata = self.get_crate_data(def.krate); + decoder::get_struct_field_names(&self.intr, &*cdata, def.index) + } + + fn item_children(&self, def_id: DefId) -> Vec + { + let mut result = vec![]; + let crate_data = self.get_crate_data(def_id.krate); + let get_crate_data = |cnum| self.get_crate_data(cnum); + decoder::each_child_of_item( + self.intr.clone(), &*crate_data, + def_id.index, get_crate_data, + |def, name, vis| result.push(ChildItem { + def: def, + name: name, + vis: vis + })); + result + } + + fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec + { + let mut result = vec![]; + let crate_data = self.get_crate_data(cnum); + let get_crate_data = |cnum| self.get_crate_data(cnum); + decoder::each_top_level_item_of_crate( + self.intr.clone(), &*crate_data, get_crate_data, + |def, name, vis| result.push(ChildItem { + def: def, + name: name, + vis: vis + })); + result + } + + fn maybe_get_item_ast(&'tcx self, tcx: &ty::ctxt<'tcx>, def: DefId) + -> FoundAst<'tcx> + { + let cdata = self.get_crate_data(def.krate); + let decode_inlined_item = Box::new(astencode::decode_inlined_item); + decoder::maybe_get_item_ast(&*cdata, tcx, def.index, decode_inlined_item) + } + + fn crates(&self) -> Vec + { + let mut result = vec![]; + self.iter_crate_data(|cnum, _| result.push(cnum)); + result + } + + fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> + { + self.get_used_libraries().borrow().clone() + } + + fn used_link_args(&self) -> Vec + { + self.get_used_link_args().borrow().clone() + } + + fn metadata_filename(&self) -> &str + { + loader::METADATA_FILENAME + } + + fn metadata_section_name(&self, target: &Target) -> &str + { + loader::meta_section_name(target) + } + fn encode_type(&self, tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Vec + { + encoder::encoded_ty(tcx, ty) + } + + fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)> + { + self.do_get_used_crates(prefer) + } + + fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource + { + self.do_get_used_crate_source(cnum).unwrap() + } + + fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option + { + self.find_extern_mod_stmt_cnum(emod_id) + } + + fn encode_metadata(&self, + tcx: &ty::ctxt<'tcx>, + reexports: &def::ExportMap, + item_symbols: &RefCell>, + link_meta: &LinkMeta, + reachable: &NodeSet, + krate: &hir::Crate) -> Vec + { + let encode_inlined_item: encoder::EncodeInlinedItem = + Box::new(|ecx, rbml_w, ii| astencode::encode_inlined_item(ecx, rbml_w, ii)); + + let encode_params = encoder::EncodeParams { + diag: tcx.sess.diagnostic(), + tcx: tcx, + reexports: reexports, + item_symbols: item_symbols, + link_meta: link_meta, + cstore: self, + encode_inlined_item: encode_inlined_item, + reachable: reachable + }; + encoder::encode_metadata(encode_params, krate) + + } + + fn metadata_encoding_version(&self) -> &[u8] + { + encoder::metadata_encoding_version + } +} diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs new file mode 100644 index 00000000000..6a1f9d16fe7 --- /dev/null +++ b/src/librustc_metadata/cstore.rs @@ -0,0 +1,345 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] + +// The crate store - a central repo for information collected about external +// crates and libraries + +pub use self::MetadataBlob::*; + +use creader; +use decoder; +use index; +use loader; + +use rustc::back::svh::Svh; +use rustc::front::map as ast_map; +use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; + +use std::cell::{RefCell, Ref, Cell}; +use std::rc::Rc; +use std::path::PathBuf; +use flate::Bytes; +use syntax::ast; +use syntax::attr; +use syntax::codemap; +use syntax::parse::token; +use syntax::parse::token::IdentInterner; +use syntax::util::small_vector::SmallVector; + +pub use middle::cstore::{NativeLibraryKind, LinkagePreference}; +pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; +pub use middle::cstore::{CrateSource, LinkMeta}; + +// A map from external crate numbers (as decoded from some crate file) to +// local crate numbers (as generated during this session). Each external +// crate may refer to types in other external crates, and each has their +// own crate numbers. +pub type cnum_map = FnvHashMap; + +pub enum MetadataBlob { + MetadataVec(Bytes), + MetadataArchive(loader::ArchiveMetadata), +} + +/// Holds information about a codemap::FileMap imported from another crate. +/// See creader::import_codemap() for more information. +pub struct ImportedFileMap { + /// This FileMap's byte-offset within the codemap of its original crate + pub original_start_pos: codemap::BytePos, + /// The end of this FileMap within the codemap of its original crate + pub original_end_pos: codemap::BytePos, + /// The imported FileMap's representation within the local codemap + pub translated_filemap: Rc +} + +pub struct crate_metadata { + pub name: String, + pub local_path: RefCell>, + pub local_def_path: RefCell, + pub data: MetadataBlob, + pub cnum_map: RefCell, + pub cnum: ast::CrateNum, + pub codemap_import_info: RefCell>, + pub span: codemap::Span, + pub staged_api: bool, + + pub index: index::Index, + pub xref_index: index::DenseIndex, + + /// Flag if this crate is required by an rlib version of this crate, or in + /// other words whether it was explicitly linked to. An example of a crate + /// where this is false is when an allocator crate is injected into the + /// dependency list, and therefore isn't actually needed to link an rlib. + pub explicitly_linked: Cell, +} + +pub struct CStore { + metas: RefCell>>, + /// Map from NodeId's of local extern crate statements to crate numbers + extern_mod_crate_map: RefCell>, + used_crate_sources: RefCell>, + used_libraries: RefCell>, + used_link_args: RefCell>, + statically_included_foreign_items: RefCell, + pub intr: Rc, +} + +impl CStore { + pub fn new(intr: Rc) -> CStore { + CStore { + metas: RefCell::new(FnvHashMap()), + extern_mod_crate_map: RefCell::new(FnvHashMap()), + used_crate_sources: RefCell::new(Vec::new()), + used_libraries: RefCell::new(Vec::new()), + used_link_args: RefCell::new(Vec::new()), + intr: intr, + statically_included_foreign_items: RefCell::new(NodeSet()), + } + } + + pub fn next_crate_num(&self) -> ast::CrateNum { + self.metas.borrow().len() as ast::CrateNum + 1 + } + + pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc { + self.metas.borrow().get(&cnum).unwrap().clone() + } + + pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh { + let cdata = self.get_crate_data(cnum); + decoder::get_crate_hash(cdata.data()) + } + + pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc) { + self.metas.borrow_mut().insert(cnum, data); + } + + pub fn iter_crate_data(&self, mut i: I) where + I: FnMut(ast::CrateNum, &Rc), + { + for (&k, v) in self.metas.borrow().iter() { + i(k, v); + } + } + + /// Like `iter_crate_data`, but passes source paths (if available) as well. + pub fn iter_crate_data_origins(&self, mut i: I) where + I: FnMut(ast::CrateNum, &crate_metadata, Option), + { + for (&k, v) in self.metas.borrow().iter() { + let origin = self.do_get_used_crate_source(k); + origin.as_ref().map(|cs| { assert!(k == cs.cnum); }); + i(k, &**v, origin); + } + } + + pub fn add_used_crate_source(&self, src: CrateSource) { + let mut used_crate_sources = self.used_crate_sources.borrow_mut(); + if !used_crate_sources.contains(&src) { + used_crate_sources.push(src); + } + } + + // TODO: killdo + pub fn do_get_used_crate_source(&self, cnum: ast::CrateNum) + -> Option { + self.used_crate_sources.borrow_mut() + .iter().find(|source| source.cnum == cnum).cloned() + } + + pub fn reset(&self) { + self.metas.borrow_mut().clear(); + self.extern_mod_crate_map.borrow_mut().clear(); + self.used_crate_sources.borrow_mut().clear(); + self.used_libraries.borrow_mut().clear(); + self.used_link_args.borrow_mut().clear(); + self.statically_included_foreign_items.borrow_mut().clear(); + } + + // This method is used when generating the command line to pass through to + // system linker. The linker expects undefined symbols on the left of the + // command line to be defined in libraries on the right, not the other way + // around. For more info, see some comments in the add_used_library function + // below. + // + // In order to get this left-to-right dependency ordering, we perform a + // topological sort of all crates putting the leaves at the right-most + // positions. + // TODO: killdo + pub fn do_get_used_crates(&self, prefer: LinkagePreference) + -> Vec<(ast::CrateNum, Option)> { + let mut ordering = Vec::new(); + fn visit(cstore: &CStore, cnum: ast::CrateNum, + ordering: &mut Vec) { + if ordering.contains(&cnum) { return } + let meta = cstore.get_crate_data(cnum); + for (_, &dep) in meta.cnum_map.borrow().iter() { + visit(cstore, dep, ordering); + } + ordering.push(cnum); + } + for (&num, _) in self.metas.borrow().iter() { + visit(self, num, &mut ordering); + } + info!("topological ordering: {:?}", ordering); + ordering.reverse(); + let mut libs = self.used_crate_sources.borrow() + .iter() + .map(|src| (src.cnum, match prefer { + LinkagePreference::RequireDynamic => src.dylib.clone().map(|p| p.0), + LinkagePreference::RequireStatic => src.rlib.clone().map(|p| p.0), + })) + .collect::>(); + libs.sort_by(|&(a, _), &(b, _)| { + let a = ordering.iter().position(|x| *x == a); + let b = ordering.iter().position(|x| *x == b); + a.cmp(&b) + }); + libs + } + + pub fn add_used_library(&self, lib: String, kind: NativeLibraryKind) { + assert!(!lib.is_empty()); + self.used_libraries.borrow_mut().push((lib, kind)); + } + + pub fn get_used_libraries<'a>(&'a self) + -> &'a RefCell> { + &self.used_libraries + } + + pub fn add_used_link_args(&self, args: &str) { + for s in args.split(' ').filter(|s| !s.is_empty()) { + self.used_link_args.borrow_mut().push(s.to_string()); + } + } + + pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell > { + &self.used_link_args + } + + pub fn add_extern_mod_stmt_cnum(&self, + emod_id: ast::NodeId, + cnum: ast::CrateNum) { + self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum); + } + + pub fn find_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) + -> Option { + self.extern_mod_crate_map.borrow().get(&emod_id).cloned() + } + + pub fn add_statically_included_foreign_item(&self, id: ast::NodeId) { + self.statically_included_foreign_items.borrow_mut().insert(id); + } + + pub fn do_is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { + self.statically_included_foreign_items.borrow().contains(&id) + } +} + +impl crate_metadata { + pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } + pub fn name(&self) -> String { decoder::get_crate_name(self.data()) } + pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) } + pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap) + -> Ref<'a, Vec> { + let filemaps = self.codemap_import_info.borrow(); + if filemaps.is_empty() { + drop(filemaps); + let filemaps = creader::import_codemap(codemap, &self.data); + + // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref. + *self.codemap_import_info.borrow_mut() = filemaps; + self.codemap_import_info.borrow() + } else { + filemaps + } + } + + pub fn with_local_path(&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; + } + }, + } + } + + pub fn local_def_path(&self) -> ast_map::DefPath { + let local_def_path = self.local_def_path.borrow(); + if local_def_path.is_empty() { + let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name)); + vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }] + } else { + local_def_path.clone() + } + } + + pub fn update_local_def_path(&self, candidate: ast_map::DefPath) { + let mut local_def_path = self.local_def_path.borrow_mut(); + if local_def_path.is_empty() || candidate.len() < local_def_path.len() { + *local_def_path = candidate; + } + } + + pub fn is_allocator(&self) -> bool { + let attrs = decoder::get_crate_attributes(self.data()); + attr::contains_name(&attrs, "allocator") + } + + pub fn needs_allocator(&self) -> bool { + let attrs = decoder::get_crate_attributes(self.data()); + attr::contains_name(&attrs, "needs_allocator") + } +} + +impl MetadataBlob { + pub fn as_slice<'a>(&'a self) -> &'a [u8] { + let slice = match *self { + MetadataVec(ref vec) => &vec[..], + MetadataArchive(ref ar) => ar.as_slice(), + }; + if slice.len() < 4 { + &[] // corrupt metadata + } else { + let len = (((slice[0] as u32) << 24) | + ((slice[1] as u32) << 16) | + ((slice[2] as u32) << 8) | + ((slice[3] as u32) << 0)) as usize; + if len + 4 <= slice.len() { + &slice[4.. len + 4] + } else { + &[] // corrupt or old metadata + } + } + } +} diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs new file mode 100644 index 00000000000..092f7849115 --- /dev/null +++ b/src/librustc_metadata/decoder.rs @@ -0,0 +1,1557 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Decoding metadata from a single crate's metadata + +#![allow(non_camel_case_types)] + +use self::Family::*; + +use cstore::{self, crate_metadata}; +use common::*; +use encoder::def_to_u64; +use index; +use tydecode::TyDecoder; + +use rustc::back::svh::Svh; +use rustc::front::map as hir_map; +use rustc::util::nodemap::FnvHashMap; +use rustc_front::hir; + +use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference}; +use middle::cstore::{DefLike, DlDef, DlField, DlImpl}; +use middle::def; +use middle::def_id::{DefId, DefIndex}; +use middle::lang_items; +use middle::subst; +use middle::ty::{ImplContainer, TraitContainer}; +use middle::ty::{self, RegionEscape, Ty}; + +use std::cell::{Cell, RefCell}; +use std::io::prelude::*; +use std::io; +use std::rc::Rc; +use std::str; + +use rbml::reader; +use rbml; +use serialize::Decodable; +use syntax::attr; +use syntax::parse::token::{IdentInterner, special_idents}; +use syntax::parse::token; +use syntax::ast; +use syntax::abi; +use syntax::codemap; +use syntax::print::pprust; +use syntax::ptr::P; + + +pub type Cmd<'a> = &'a crate_metadata; + +impl crate_metadata { + fn get_item(&self, item_id: DefIndex) -> Option { + self.index.lookup_item(self.data(), item_id).map(|pos| { + reader::doc_at(self.data(), pos as usize).unwrap().doc + }) + } + + fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc { + match self.get_item(item_id) { + None => panic!("lookup_item: id not found: {:?}", item_id), + Some(d) => d + } + } +} + +pub fn load_index(data: &[u8]) -> index::Index { + let index = reader::get_doc(rbml::Doc::new(data), tag_index); + index::Index::from_rbml(index) +} + +pub fn crate_rustc_version(data: &[u8]) -> Option { + let doc = rbml::Doc::new(data); + reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str()) +} + +pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { + let index = reader::get_doc(rbml::Doc::new(data), tag_xref_index); + index::DenseIndex::from_buf(index.data, index.start, index.end) +} + +#[derive(Debug, PartialEq)] +enum Family { + ImmStatic, // c + MutStatic, // b + Fn, // f + CtorFn, // o + StaticMethod, // F + Method, // h + Type, // y + Mod, // m + ForeignMod, // n + Enum, // t + TupleVariant, // v + StructVariant, // V + Impl, // i + DefaultImpl, // d + Trait, // I + Struct, // S + PublicField, // g + InheritedField, // N + Constant, // C +} + +fn item_family(item: rbml::Doc) -> Family { + let fam = reader::get_doc(item, tag_items_data_item_family); + match reader::doc_as_u8(fam) as char { + 'C' => Constant, + 'c' => ImmStatic, + 'b' => MutStatic, + 'f' => Fn, + 'o' => CtorFn, + 'F' => StaticMethod, + 'h' => Method, + 'y' => Type, + 'm' => Mod, + 'n' => ForeignMod, + 't' => Enum, + 'v' => TupleVariant, + 'V' => StructVariant, + 'i' => Impl, + 'd' => DefaultImpl, + 'I' => Trait, + 'S' => Struct, + 'g' => PublicField, + 'N' => InheritedField, + c => panic!("unexpected family char: {}", c) + } +} + +fn item_visibility(item: rbml::Doc) -> hir::Visibility { + match reader::maybe_get_doc(item, tag_items_data_item_visibility) { + None => hir::Public, + Some(visibility_doc) => { + match reader::doc_as_u8(visibility_doc) as char { + 'y' => hir::Public, + 'i' => hir::Inherited, + _ => panic!("unknown visibility character") + } + } + } +} + +fn fn_constness(item: rbml::Doc) -> hir::Constness { + match reader::maybe_get_doc(item, tag_items_data_item_constness) { + None => hir::Constness::NotConst, + Some(constness_doc) => { + match reader::doc_as_u8(constness_doc) as char { + 'c' => hir::Constness::Const, + 'n' => hir::Constness::NotConst, + _ => panic!("unknown constness character") + } + } + } +} + +fn item_sort(item: rbml::Doc) -> Option { + reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| { + doc.as_str_slice().as_bytes()[0] as char + }) +} + +fn item_symbol(item: rbml::Doc) -> String { + reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string() +} + +fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { + let id = reader::doc_as_u64(d); + let index = DefIndex::new((id & 0xFFFF_FFFF) as usize); + let def_id = DefId { krate: (id >> 32) as u32, index: index }; + translate_def_id(cdata, def_id) +} + +fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { + reader::tagged_docs(d, tag_items_data_parent_item).nth(0).map(|did| { + translated_def_id(cdata, did) + }) +} + +fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId { + translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item)) +} + +fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId { + translated_def_id(cdata, reader::get_doc(d, tag_def_id)) +} + +fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> { + reader::tagged_docs(d, tag_items_data_item_reexport) +} + +fn variant_disr_val(d: rbml::Doc) -> Option { + reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| { + reader::with_doc_data(val_doc, |data| { + str::from_utf8(data).ok().and_then(|s| s.parse().ok()) + }) + }) +} + +fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> { + let tp = reader::get_doc(doc, tag_items_data_item_type); + TyDecoder::with_doc(tcx, cdata.cnum, tp, + &mut |did| translate_def_id(cdata, did)) + .parse_ty() +} + +fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option> { + reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| { + TyDecoder::with_doc(tcx, cdata.cnum, tp, + &mut |did| translate_def_id(cdata, did)) + .parse_ty() + }) +} + +pub fn item_type<'tcx>(_item_id: DefId, item: rbml::Doc, + tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> { + doc_type(item, tcx, cdata) +} + +fn doc_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) + -> ty::TraitRef<'tcx> { + TyDecoder::with_doc(tcx, cdata.cnum, doc, + &mut |did| translate_def_id(cdata, did)) + .parse_trait_ref() +} + +fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) + -> ty::TraitRef<'tcx> { + let tp = reader::get_doc(doc, tag_item_trait_ref); + doc_trait_ref(tp, tcx, cdata) +} + +fn item_path(item_doc: rbml::Doc) -> Vec { + let path_doc = reader::get_doc(item_doc, tag_path); + reader::docs(path_doc).filter_map(|(tag, elt_doc)| { + if tag == tag_path_elem_mod { + let s = elt_doc.as_str_slice(); + Some(hir_map::PathMod(token::intern(s))) + } else if tag == tag_path_elem_name { + let s = elt_doc.as_str_slice(); + Some(hir_map::PathName(token::intern(s))) + } else { + // ignore tag_path_len element + None + } + }).collect() +} + +fn item_name(intr: &IdentInterner, item: rbml::Doc) -> ast::Name { + let name = reader::get_doc(item, tag_paths_data_name); + let string = name.as_str_slice(); + match intr.find(string) { + None => token::intern(string), + Some(val) => val, + } +} + +fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike { + let fam = item_family(item); + match fam { + Constant => { + // Check whether we have an associated const item. + match item_sort(item) { + Some('C') | Some('c') => { + DlDef(def::DefAssociatedConst(did)) + } + _ => { + // Regular const item. + DlDef(def::DefConst(did)) + } + } + } + ImmStatic => DlDef(def::DefStatic(did, false)), + MutStatic => DlDef(def::DefStatic(did, true)), + Struct => DlDef(def::DefStruct(did)), + Fn => DlDef(def::DefFn(did, false)), + CtorFn => DlDef(def::DefFn(did, true)), + Method | StaticMethod => { + DlDef(def::DefMethod(did)) + } + Type => { + if item_sort(item) == Some('t') { + let trait_did = item_require_parent_item(cdata, item); + DlDef(def::DefAssociatedTy(trait_did, did)) + } else { + DlDef(def::DefTy(did, false)) + } + } + Mod => DlDef(def::DefMod(did)), + ForeignMod => DlDef(def::DefForeignMod(did)), + StructVariant => { + let enum_did = item_require_parent_item(cdata, item); + DlDef(def::DefVariant(enum_did, did, true)) + } + TupleVariant => { + let enum_did = item_require_parent_item(cdata, item); + DlDef(def::DefVariant(enum_did, did, false)) + } + Trait => DlDef(def::DefTrait(did)), + Enum => DlDef(def::DefTy(did, true)), + Impl | DefaultImpl => DlImpl(did), + PublicField | InheritedField => DlField, + } +} + +fn parse_unsafety(item_doc: rbml::Doc) -> hir::Unsafety { + let unsafety_doc = reader::get_doc(item_doc, tag_unsafety); + if reader::doc_as_u8(unsafety_doc) != 0 { + hir::Unsafety::Unsafe + } else { + hir::Unsafety::Normal + } +} + +fn parse_paren_sugar(item_doc: rbml::Doc) -> bool { + let paren_sugar_doc = reader::get_doc(item_doc, tag_paren_sugar); + reader::doc_as_u8(paren_sugar_doc) != 0 +} + +fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity { + let polarity_doc = reader::get_doc(item_doc, tag_polarity); + if reader::doc_as_u8(polarity_doc) != 0 { + hir::ImplPolarity::Negative + } else { + hir::ImplPolarity::Positive + } +} + +fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { + let names_doc = reader::get_doc(item_doc, tag_associated_type_names); + reader::tagged_docs(names_doc, tag_associated_type_name) + .map(|name_doc| token::intern(name_doc.as_str_slice())) + .collect() +} + +pub fn get_trait_def<'tcx>(cdata: Cmd, + item_id: DefIndex, + tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx> +{ + let item_doc = cdata.lookup_item(item_id); + let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); + let unsafety = parse_unsafety(item_doc); + let associated_type_names = parse_associated_type_names(item_doc); + let paren_sugar = parse_paren_sugar(item_doc); + + ty::TraitDef { + paren_sugar: paren_sugar, + unsafety: unsafety, + generics: generics, + trait_ref: item_trait_ref(item_doc, tcx, cdata), + associated_type_names: associated_type_names, + nonblanket_impls: RefCell::new(FnvHashMap()), + blanket_impls: RefCell::new(vec![]), + flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS) + } +} + +pub fn get_adt_def<'tcx>(intr: &IdentInterner, + cdata: Cmd, + item_id: DefIndex, + tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx> +{ + fn get_enum_variants<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>) -> Vec> { + let mut disr_val = 0; + reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| { + let did = translated_def_id(cdata, p); + let item = cdata.lookup_item(did.index); + + if let Some(disr) = variant_disr_val(item) { + disr_val = disr; + } + let disr = disr_val; + disr_val = disr_val.wrapping_add(1); + + ty::VariantDefData { + did: did, + name: item_name(intr, item), + fields: get_variant_fields(intr, cdata, item, tcx), + disr_val: disr + } + }).collect() + } + fn get_variant_fields<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>) -> Vec> { + reader::tagged_docs(doc, tag_item_field).map(|f| { + let ff = item_family(f); + match ff { + PublicField | InheritedField => {}, + _ => tcx.sess.bug(&format!("expected field, found {:?}", ff)) + }; + ty::FieldDefData::new(item_def_id(f, cdata), + item_name(intr, f), + struct_field_family_to_visibility(ff)) + }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| { + let ff = item_family(f); + ty::FieldDefData::new(item_def_id(f, cdata), + special_idents::unnamed_field.name, + struct_field_family_to_visibility(ff)) + })).collect() + } + fn get_struct_variant<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + did: DefId, + tcx: &ty::ctxt<'tcx>) -> ty::VariantDefData<'tcx, 'tcx> { + ty::VariantDefData { + did: did, + name: item_name(intr, doc), + fields: get_variant_fields(intr, cdata, doc, tcx), + disr_val: 0 + } + } + + let doc = cdata.lookup_item(item_id); + let did = DefId { krate: cdata.cnum, index: item_id }; + let (kind, variants) = match item_family(doc) { + Enum => { + (ty::AdtKind::Enum, + get_enum_variants(intr, cdata, doc, tcx)) + } + Struct => { + let ctor_did = + reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor). + map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc)); + (ty::AdtKind::Struct, + vec![get_struct_variant(intr, cdata, doc, ctor_did, tcx)]) + } + _ => tcx.sess.bug( + &format!("get_adt_def called on a non-ADT {:?} - {:?}", + item_family(doc), did)) + }; + + let adt = tcx.intern_adt_def(did, kind, variants); + + // this needs to be done *after* the variant is interned, + // to support recursive structures + for variant in &adt.variants { + if variant.kind() == ty::VariantKind::Tuple && + adt.adt_kind() == ty::AdtKind::Enum { + // tuple-like enum variant fields aren't real items - get the types + // from the ctor. + debug!("evaluating the ctor-type of {:?}", + variant.name); + let ctor_ty = get_type(cdata, variant.did.index, tcx).ty; + debug!("evaluating the ctor-type of {:?}.. {:?}", + variant.name, + ctor_ty); + let field_tys = match ctor_ty.sty { + ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + ref inputs, .. + }), ..}) => { + // tuple-struct constructors don't have escaping regions + assert!(!inputs.has_escaping_regions()); + inputs + }, + _ => tcx.sess.bug("tuple-variant ctor is not an ADT") + }; + for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) { + field.fulfill_ty(ty); + } + } else { + for field in &variant.fields { + debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); + let ty = get_type(cdata, field.did.index, tcx).ty; + field.fulfill_ty(ty); + debug!("evaluating the type of {:?}::{:?}: {:?}", + variant.name, field.name, ty); + } + } + } + + adt +} + +pub fn get_predicates<'tcx>(cdata: Cmd, + item_id: DefIndex, + tcx: &ty::ctxt<'tcx>) + -> ty::GenericPredicates<'tcx> +{ + let item_doc = cdata.lookup_item(item_id); + doc_predicates(item_doc, tcx, cdata, tag_item_generics) +} + +pub fn get_super_predicates<'tcx>(cdata: Cmd, + item_id: DefIndex, + tcx: &ty::ctxt<'tcx>) + -> ty::GenericPredicates<'tcx> +{ + let item_doc = cdata.lookup_item(item_id); + doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates) +} + +pub fn get_type<'tcx>(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt<'tcx>) + -> ty::TypeScheme<'tcx> +{ + let item_doc = cdata.lookup_item(id); + let t = item_type(DefId { krate: cdata.cnum, index: id }, item_doc, tcx, + cdata); + let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); + ty::TypeScheme { + generics: generics, + ty: t + } +} + +pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { + let item = cdata.lookup_item(id); + reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| { + let mut decoder = reader::Decoder::new(doc); + Decodable::decode(&mut decoder).unwrap() + }) +} + +pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { + let item = cdata.lookup_item(id); + match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| { + let mut decoder = reader::Decoder::new(doc); + Decodable::decode(&mut decoder).unwrap() + }) { + Some(attrs) => attrs, + None => Vec::new(), + } +} + +pub fn get_impl_polarity<'tcx>(cdata: Cmd, + id: DefIndex) + -> Option +{ + let item_doc = cdata.lookup_item(id); + let fam = item_family(item_doc); + match fam { + Family::Impl => { + Some(parse_polarity(item_doc)) + } + _ => None + } +} + +pub fn get_custom_coerce_unsized_kind<'tcx>( + cdata: Cmd, + id: DefIndex) + -> Option +{ + let item_doc = cdata.lookup_item(id); + reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { + let mut decoder = reader::Decoder::new(kind_doc); + Decodable::decode(&mut decoder).unwrap() + }) +} + +pub fn get_impl_trait<'tcx>(cdata: Cmd, + id: DefIndex, + tcx: &ty::ctxt<'tcx>) + -> Option> +{ + let item_doc = cdata.lookup_item(id); + let fam = item_family(item_doc); + match fam { + Family::Impl | Family::DefaultImpl => { + reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { + doc_trait_ref(tp, tcx, cdata) + }) + } + _ => None + } +} + +pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String { + return item_symbol(cdata.lookup_item(id)); +} + +/// If you have a crate_metadata, call get_symbol instead +pub fn get_symbol_from_buf(data: &[u8], id: DefIndex) -> String { + let index = load_index(data); + let pos = index.lookup_item(data, id).unwrap(); + let doc = reader::doc_at(data, pos as usize).unwrap().doc; + item_symbol(doc) +} + +/// Iterates over the language items in the given crate. +pub fn each_lang_item(cdata: Cmd, mut f: F) -> bool where + F: FnMut(DefIndex, usize) -> bool, +{ + let root = rbml::Doc::new(cdata.data()); + let lang_items = reader::get_doc(root, tag_lang_items); + reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| { + let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id); + let id = reader::doc_as_u32(id_doc) as usize; + let index_doc = reader::get_doc(item_doc, tag_lang_items_item_index); + let index = DefIndex::from_u32(reader::doc_as_u32(index_doc)); + + f(index, id) + }) +} + +fn each_child_of_item_or_crate(intr: Rc, + cdata: Cmd, + item_doc: rbml::Doc, + mut get_crate_data: G, + mut callback: F) where + F: FnMut(DefLike, ast::Name, hir::Visibility), + G: FnMut(ast::CrateNum) -> Rc, +{ + // Iterate over all children. + for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) { + let child_def_id = translated_def_id(cdata, child_info_doc); + + // This item may be in yet another crate if it was the child of a + // reexport. + let crate_data = if child_def_id.krate == cdata.cnum { + None + } else { + Some(get_crate_data(child_def_id.krate)) + }; + let crate_data = match crate_data { + Some(ref cdata) => &**cdata, + None => cdata + }; + + // Get the item. + match crate_data.get_item(child_def_id.index) { + None => {} + Some(child_item_doc) => { + // Hand off the item to the callback. + let child_name = item_name(&*intr, child_item_doc); + let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); + let visibility = item_visibility(child_item_doc); + callback(def_like, child_name, visibility); + } + } + } + + // As a special case, iterate over all static methods of + // associated implementations too. This is a bit of a botch. + // --pcwalton + for inherent_impl_def_id_doc in reader::tagged_docs(item_doc, + tag_items_data_item_inherent_impl) { + let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata); + if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.index) { + for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc, + tag_item_impl_item) { + let impl_item_def_id = item_def_id(impl_item_def_id_doc, + cdata); + if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.index) { + if let StaticMethod = item_family(impl_method_doc) { + // Hand off the static method to the callback. + let static_method_name = item_name(&*intr, impl_method_doc); + let static_method_def_like = item_to_def_like(cdata, impl_method_doc, + impl_item_def_id); + callback(static_method_def_like, + static_method_name, + item_visibility(impl_method_doc)); + } + } + } + } + } + + for reexport_doc in reexports(item_doc) { + let def_id_doc = reader::get_doc(reexport_doc, + tag_items_data_item_reexport_def_id); + let child_def_id = translated_def_id(cdata, def_id_doc); + + let name_doc = reader::get_doc(reexport_doc, + tag_items_data_item_reexport_name); + let name = name_doc.as_str_slice(); + + // This reexport may be in yet another crate. + let crate_data = if child_def_id.krate == cdata.cnum { + None + } else { + Some(get_crate_data(child_def_id.krate)) + }; + let crate_data = match crate_data { + Some(ref cdata) => &**cdata, + None => cdata + }; + + // Get the item. + if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) { + // Hand off the item to the callback. + let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); + // These items have a public visibility because they're part of + // a public re-export. + callback(def_like, token::intern(name), hir::Public); + } + } +} + +/// Iterates over each child of the given item. +pub fn each_child_of_item(intr: Rc, + cdata: Cmd, + id: DefIndex, + get_crate_data: G, + callback: F) where + F: FnMut(DefLike, ast::Name, hir::Visibility), + G: FnMut(ast::CrateNum) -> Rc, +{ + // Find the item. + let item_doc = match cdata.get_item(id) { + None => return, + Some(item_doc) => item_doc, + }; + + each_child_of_item_or_crate(intr, + cdata, + item_doc, + get_crate_data, + callback) +} + +/// Iterates over all the top-level crate items. +pub fn each_top_level_item_of_crate(intr: Rc, + cdata: Cmd, + get_crate_data: G, + callback: F) where + F: FnMut(DefLike, ast::Name, hir::Visibility), + G: FnMut(ast::CrateNum) -> Rc, +{ + let root_doc = rbml::Doc::new(cdata.data()); + let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); + let crate_items_doc = reader::get_doc(misc_info_doc, + tag_misc_info_crate_items); + + each_child_of_item_or_crate(intr, + cdata, + crate_items_doc, + get_crate_data, + callback) +} + +pub fn get_item_path(cdata: Cmd, id: DefIndex) -> Vec { + item_path(cdata.lookup_item(id)) +} + +pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: DefIndex) -> ast::Name { + item_name(intr, cdata.lookup_item(id)) +} + +pub type DecodeInlinedItem<'a> = + Box FnMut(Cmd, + &ty::ctxt<'tcx>, + Vec, + hir_map::DefPath, + rbml::Doc, + DefId) + -> Result<&'tcx InlinedItem, (Vec, + hir_map::DefPath)> + 'a>; + +pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex, + mut decode_inlined_item: DecodeInlinedItem) + -> FoundAst<'tcx> { + debug!("Looking up item: {:?}", id); + let item_doc = cdata.lookup_item(id); + let item_did = item_def_id(item_doc, cdata); + let path = item_path(item_doc).split_last().unwrap().1.to_vec(); + let def_path = def_path(cdata, id); + match decode_inlined_item(cdata, tcx, path, def_path, item_doc, item_did) { + Ok(ii) => FoundAst::Found(ii), + Err((path, def_path)) => { + match item_parent_item(cdata, item_doc) { + Some(did) => { + let parent_item = cdata.lookup_item(did.index); + match decode_inlined_item(cdata, tcx, path, def_path, parent_item, did) { + Ok(ii) => FoundAst::FoundParent(did, ii), + Err(_) => FoundAst::NotFound + } + } + None => FoundAst::NotFound + } + } + } +} + +fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { + fn get_mutability(ch: u8) -> hir::Mutability { + match ch as char { + 'i' => hir::MutImmutable, + 'm' => hir::MutMutable, + _ => panic!("unknown mutability character: `{}`", ch as char), + } + } + + let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self); + let string = explicit_self_doc.as_str_slice(); + + let explicit_self_kind = string.as_bytes()[0]; + match explicit_self_kind as char { + 's' => ty::StaticExplicitSelfCategory, + 'v' => ty::ByValueExplicitSelfCategory, + '~' => ty::ByBoxExplicitSelfCategory, + // FIXME(#4846) expl. region + '&' => { + ty::ByReferenceExplicitSelfCategory( + ty::ReEmpty, + get_mutability(string.as_bytes()[1])) + } + _ => panic!("unknown self type code: `{}`", explicit_self_kind as char) + } +} + +/// Returns the def IDs of all the items in the given implementation. +pub fn get_impl_items(cdata: Cmd, impl_id: DefIndex) + -> Vec { + reader::tagged_docs(cdata.lookup_item(impl_id), tag_item_impl_item).map(|doc| { + let def_id = item_def_id(doc, cdata); + match item_sort(doc) { + Some('C') | Some('c') => ty::ConstTraitItemId(def_id), + Some('r') | Some('p') => ty::MethodTraitItemId(def_id), + Some('t') => ty::TypeTraitItemId(def_id), + _ => panic!("unknown impl item sort"), + } + }).collect() +} + +pub fn get_trait_name(intr: Rc, + cdata: Cmd, + id: DefIndex) + -> ast::Name { + let doc = cdata.lookup_item(id); + item_name(&*intr, doc) +} + +pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool { + let doc = cdata.lookup_item(id); + match item_sort(doc) { + Some('r') | Some('p') => { + get_explicit_self(doc) == ty::StaticExplicitSelfCategory + } + _ => false + } +} + +pub fn get_impl_or_trait_item<'tcx>(intr: Rc, + cdata: Cmd, + id: DefIndex, + tcx: &ty::ctxt<'tcx>) + -> ty::ImplOrTraitItem<'tcx> { + let item_doc = cdata.lookup_item(id); + + let def_id = item_def_id(item_doc, cdata); + + let container_id = item_require_parent_item(cdata, item_doc); + let container_doc = cdata.lookup_item(container_id.index); + let container = match item_family(container_doc) { + Trait => TraitContainer(container_id), + _ => ImplContainer(container_id), + }; + + let name = item_name(&*intr, item_doc); + let vis = item_visibility(item_doc); + + match item_sort(item_doc) { + sort @ Some('C') | sort @ Some('c') => { + let ty = doc_type(item_doc, tcx, cdata); + ty::ConstTraitItem(Rc::new(ty::AssociatedConst { + name: name, + ty: ty, + vis: vis, + def_id: def_id, + container: container, + has_value: sort == Some('C') + })) + } + Some('r') | Some('p') => { + let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics); + let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics); + let ity = tcx.lookup_item_type(def_id).ty; + let fty = match ity.sty { + ty::TyBareFn(_, fty) => fty.clone(), + _ => tcx.sess.bug(&format!( + "the type {:?} of the method {:?} is not a function?", + ity, name)) + }; + let explicit_self = get_explicit_self(item_doc); + + ty::MethodTraitItem(Rc::new(ty::Method::new(name, + generics, + predicates, + fty, + explicit_self, + vis, + def_id, + container))) + } + Some('t') => { + let ty = maybe_doc_type(item_doc, tcx, cdata); + ty::TypeTraitItem(Rc::new(ty::AssociatedType { + name: name, + ty: ty, + vis: vis, + def_id: def_id, + container: container, + })) + } + _ => panic!("unknown impl/trait item sort"), + } +} + +pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex) + -> Vec { + let item = cdata.lookup_item(id); + reader::tagged_docs(item, tag_item_trait_item).map(|mth| { + let def_id = item_def_id(mth, cdata); + match item_sort(mth) { + Some('C') | Some('c') => ty::ConstTraitItemId(def_id), + Some('r') | Some('p') => ty::MethodTraitItemId(def_id), + Some('t') => ty::TypeTraitItemId(def_id), + _ => panic!("unknown trait item sort"), + } + }).collect() +} + +pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances { + let item_doc = cdata.lookup_item(id); + let variance_doc = reader::get_doc(item_doc, tag_item_variances); + let mut decoder = reader::Decoder::new(variance_doc); + Decodable::decode(&mut decoder).unwrap() +} + +pub fn get_provided_trait_methods<'tcx>(intr: Rc, + cdata: Cmd, + id: DefIndex, + tcx: &ty::ctxt<'tcx>) + -> Vec>> { + let item = cdata.lookup_item(id); + + reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| { + let did = item_def_id(mth_id, cdata); + let mth = cdata.lookup_item(did.index); + + if item_sort(mth) == Some('p') { + let trait_item = get_impl_or_trait_item(intr.clone(), + cdata, + did.index, + tcx); + if let ty::MethodTraitItem(ref method) = trait_item { + Some((*method).clone()) + } else { + None + } + } else { + None + } + }).collect() +} + +pub fn get_associated_consts<'tcx>(intr: Rc, + cdata: Cmd, + id: DefIndex, + tcx: &ty::ctxt<'tcx>) + -> Vec>> { + let item = cdata.lookup_item(id); + + [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| { + reader::tagged_docs(item, tag).filter_map(|ac_id| { + let did = item_def_id(ac_id, cdata); + let ac_doc = cdata.lookup_item(did.index); + + match item_sort(ac_doc) { + Some('C') | Some('c') => { + let trait_item = get_impl_or_trait_item(intr.clone(), + cdata, + did.index, + tcx); + if let ty::ConstTraitItem(ref ac) = trait_item { + Some((*ac).clone()) + } else { + None + } + } + _ => None + } + }) + }).collect() +} + +/// If node_id is the constructor of a tuple struct, retrieve the NodeId of +/// the actual type definition, otherwise, return None +pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, + node_id: DefIndex) + -> Option +{ + let item = cdata.lookup_item(node_id); + reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor).next().map(|_| { + item_require_parent_item(cdata, item) + }) +} + +pub fn get_item_attrs(cdata: Cmd, + orig_node_id: DefIndex) + -> Vec { + // The attributes for a tuple struct are attached to the definition, not the ctor; + // we assume that someone passing in a tuple struct ctor is actually wanting to + // look at the definition + let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id); + let node_id = node_id.map(|x| x.index).unwrap_or(orig_node_id); + let item = cdata.lookup_item(node_id); + get_attributes(item) +} + +pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap> { + let data = rbml::Doc::new(cdata.data()); + let fields = reader::get_doc(data, tag_struct_fields); + reader::tagged_docs(fields, tag_struct_field).map(|field| { + let def_id = translated_def_id(cdata, reader::get_doc(field, tag_def_id)); + let attrs = get_attributes(field); + (def_id, attrs) + }).collect() +} + +fn struct_field_family_to_visibility(family: Family) -> hir::Visibility { + match family { + PublicField => hir::Public, + InheritedField => hir::Inherited, + _ => panic!() + } +} + +pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: DefIndex) + -> Vec { + let item = cdata.lookup_item(id); + reader::tagged_docs(item, tag_item_field).map(|an_item| { + item_name(intr, an_item) + }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|_| { + special_idents::unnamed_field.name + })).collect() +} + +fn get_meta_items(md: rbml::Doc) -> Vec> { + reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| { + let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); + let n = token::intern_and_get_ident(nd.as_str_slice()); + attr::mk_word_item(n) + }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| { + let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); + let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); + let n = token::intern_and_get_ident(nd.as_str_slice()); + let v = token::intern_and_get_ident(vd.as_str_slice()); + // FIXME (#623): Should be able to decode MetaNameValue variants, + // but currently the encoder just drops them + attr::mk_name_value_item_str(n, v) + })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| { + let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); + let n = token::intern_and_get_ident(nd.as_str_slice()); + let subitems = get_meta_items(meta_item_doc); + attr::mk_list_item(n, subitems) + })).collect() +} + +fn get_attributes(md: rbml::Doc) -> Vec { + match reader::maybe_get_doc(md, tag_attributes) { + Some(attrs_d) => { + reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| { + let is_sugared_doc = reader::doc_as_u8( + reader::get_doc(attr_doc, tag_attribute_is_sugared_doc) + ) == 1; + let meta_items = get_meta_items(attr_doc); + // Currently it's only possible to have a single meta item on + // an attribute + assert_eq!(meta_items.len(), 1); + let meta_item = meta_items.into_iter().nth(0).unwrap(); + codemap::Spanned { + node: ast::Attribute_ { + id: attr::mk_attr_id(), + style: ast::AttrStyle::Outer, + value: meta_item, + is_sugared_doc: is_sugared_doc, + }, + span: codemap::DUMMY_SP + } + }).collect() + }, + None => vec![], + } +} + +fn list_crate_attributes(md: rbml::Doc, hash: &Svh, + out: &mut io::Write) -> io::Result<()> { + try!(write!(out, "=Crate Attributes ({})=\n", *hash)); + + let r = get_attributes(md); + for attr in &r { + try!(write!(out, "{}\n", pprust::attribute_to_string(attr))); + } + + write!(out, "\n\n") +} + +pub fn get_crate_attributes(data: &[u8]) -> Vec { + get_attributes(rbml::Doc::new(data)) +} + +#[derive(Clone)] +pub struct CrateDep { + pub cnum: ast::CrateNum, + pub name: String, + pub hash: Svh, + pub explicitly_linked: bool, +} + +pub fn get_crate_deps(data: &[u8]) -> Vec { + let cratedoc = rbml::Doc::new(data); + let depsdoc = reader::get_doc(cratedoc, tag_crate_deps); + + fn docstr(doc: rbml::Doc, tag_: usize) -> String { + let d = reader::get_doc(doc, tag_); + d.as_str_slice().to_string() + } + + reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { + let name = docstr(depdoc, tag_crate_dep_crate_name); + let hash = Svh::new(&docstr(depdoc, tag_crate_dep_hash)); + let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked); + let explicitly_linked = reader::doc_as_u8(doc) != 0; + CrateDep { + cnum: crate_num as u32 + 1, + name: name, + hash: hash, + explicitly_linked: explicitly_linked, + } + }).collect() +} + +fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { + try!(write!(out, "=External Dependencies=\n")); + for dep in &get_crate_deps(data) { + try!(write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash)); + } + try!(write!(out, "\n")); + Ok(()) +} + +pub fn maybe_get_crate_hash(data: &[u8]) -> Option { + let cratedoc = rbml::Doc::new(data); + reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { + Svh::new(doc.as_str_slice()) + }) +} + +pub fn get_crate_hash(data: &[u8]) -> Svh { + let cratedoc = rbml::Doc::new(data); + let hashdoc = reader::get_doc(cratedoc, tag_crate_hash); + Svh::new(hashdoc.as_str_slice()) +} + +pub fn maybe_get_crate_name(data: &[u8]) -> Option { + let cratedoc = rbml::Doc::new(data); + reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| { + doc.as_str_slice().to_string() + }) +} + +pub fn get_crate_triple(data: &[u8]) -> Option { + let cratedoc = rbml::Doc::new(data); + let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple); + triple_doc.map(|s| s.as_str().to_string()) +} + +pub fn get_crate_name(data: &[u8]) -> String { + maybe_get_crate_name(data).expect("no crate name in crate") +} + +pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> { + let hash = get_crate_hash(bytes); + let md = rbml::Doc::new(bytes); + try!(list_crate_attributes(md, &hash, out)); + list_crate_deps(bytes, out) +} + +// Translates a def_id from an external crate to a def_id for the current +// compilation environment. We use this when trying to load types from +// external crates - if those types further refer to types in other crates +// then we must translate the crate number from that encoded in the external +// crate to the correct local crate number. +pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId { + if did.is_local() { + return DefId { krate: cdata.cnum, index: did.index }; + } + + match cdata.cnum_map.borrow().get(&did.krate) { + Some(&n) => { + DefId { + krate: n, + index: did.index, + } + } + None => panic!("didn't find a crate in the cnum_map") + } +} + +// Translate a DefId from the current compilation environment to a DefId +// for an external crate. +fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { + if did.krate == cdata.cnum { + return Some(DefId { krate: LOCAL_CRATE, index: did.index }); + } + + for (&local, &global) in cdata.cnum_map.borrow().iter() { + if global == did.krate { + return Some(DefId { krate: local, index: did.index }); + } + } + + None +} + +pub fn each_inherent_implementation_for_type(cdata: Cmd, + id: DefIndex, + mut callback: F) + where F: FnMut(DefId), +{ + let item_doc = cdata.lookup_item(id); + for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) { + if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() { + callback(item_def_id(impl_doc, cdata)); + } + } +} + +pub fn each_implementation_for_trait(cdata: Cmd, + def_id: DefId, + mut callback: F) where + F: FnMut(DefId), +{ + // Do a reverse lookup beforehand to avoid touching the crate_num + // hash map in the loop below. + if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) { + let def_id_u64 = def_to_u64(crate_local_did); + + let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls); + for trait_doc in reader::tagged_docs(impls_doc, tag_impls_trait) { + let trait_def_id = reader::get_doc(trait_doc, tag_def_id); + if reader::doc_as_u64(trait_def_id) != def_id_u64 { + continue; + } + for impl_doc in reader::tagged_docs(trait_doc, tag_impls_trait_impl) { + callback(translated_def_id(cdata, impl_doc)); + } + } + } +} + +pub fn get_trait_of_item(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) + -> Option { + let item_doc = cdata.lookup_item(id); + let parent_item_id = match item_parent_item(cdata, item_doc) { + None => return None, + Some(item_id) => item_id, + }; + let parent_item_doc = cdata.lookup_item(parent_item_id.index); + match item_family(parent_item_doc) { + Trait => Some(item_def_id(parent_item_doc, cdata)), + Impl | DefaultImpl => { + reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref) + .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id) + } + _ => None + } +} + + +pub fn get_native_libraries(cdata: Cmd) + -> Vec<(cstore::NativeLibraryKind, String)> { + let libraries = reader::get_doc(rbml::Doc::new(cdata.data()), + tag_native_libraries); + reader::tagged_docs(libraries, tag_native_libraries_lib).map(|lib_doc| { + let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind); + let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name); + let kind: cstore::NativeLibraryKind = + cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap(); + let name = name_doc.as_str().to_string(); + (kind, name) + }).collect() +} + +pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { + reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn) + .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc))) +} + +pub fn each_exported_macro(data: &[u8], intr: &IdentInterner, mut f: F) where + F: FnMut(ast::Name, Vec, String) -> bool, +{ + let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs); + for macro_doc in reader::tagged_docs(macros, tag_macro_def) { + let name = item_name(intr, macro_doc); + let attrs = get_attributes(macro_doc); + let body = reader::get_doc(macro_doc, tag_macro_def_body); + if !f(name, attrs, body.as_str().to_string()) { + break; + } + } +} + +pub fn get_dylib_dependency_formats(cdata: Cmd) + -> Vec<(ast::CrateNum, LinkagePreference)> +{ + let formats = reader::get_doc(rbml::Doc::new(cdata.data()), + tag_dylib_dependency_formats); + let mut result = Vec::new(); + + debug!("found dylib deps: {}", formats.as_str_slice()); + for spec in formats.as_str_slice().split(',') { + if spec.is_empty() { continue } + let cnum = spec.split(':').nth(0).unwrap(); + let link = spec.split(':').nth(1).unwrap(); + let cnum: ast::CrateNum = cnum.parse().unwrap(); + let cnum = match cdata.cnum_map.borrow().get(&cnum) { + Some(&n) => n, + None => panic!("didn't find a crate in the cnum_map") + }; + result.push((cnum, if link == "d" { + LinkagePreference::RequireDynamic + } else { + LinkagePreference::RequireStatic + })); + } + return result; +} + +pub fn get_missing_lang_items(cdata: Cmd) + -> Vec +{ + let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_lang_items); + reader::tagged_docs(items, tag_lang_items_missing).map(|missing_docs| { + lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap() + }).collect() +} + +pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { + let method_doc = cdata.lookup_item(id); + match reader::maybe_get_doc(method_doc, tag_method_argument_names) { + Some(args_doc) => { + reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| { + name_doc.as_str_slice().to_string() + }).collect() + }, + None => vec![], + } +} + +pub fn get_reachable_ids(cdata: Cmd) -> Vec { + let items = reader::get_doc(rbml::Doc::new(cdata.data()), + tag_reachable_ids); + reader::tagged_docs(items, tag_reachable_id).map(|doc| { + DefId { + krate: cdata.cnum, + index: DefIndex::from_u32(reader::doc_as_u32(doc)), + } + }).collect() +} + +pub fn is_typedef(cdata: Cmd, id: DefIndex) -> bool { + let item_doc = cdata.lookup_item(id); + match item_family(item_doc) { + Type => true, + _ => false, + } +} + +pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool { + let item_doc = cdata.lookup_item(id); + match fn_constness(item_doc) { + hir::Constness::Const => true, + hir::Constness::NotConst => false, + } +} + +pub fn is_static(cdata: Cmd, id: DefIndex) -> bool { + let item_doc = cdata.lookup_item(id); + match item_family(item_doc) { + ImmStatic | MutStatic => true, + _ => false, + } +} + +pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool { + let item_doc = cdata.lookup_item(id); + match item_family(item_doc) { + Impl => true, + _ => false, + } +} + +fn doc_generics<'tcx>(base_doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>, + cdata: Cmd, + tag: usize) + -> ty::Generics<'tcx> +{ + let doc = reader::get_doc(base_doc, tag); + + let mut types = subst::VecPerParamSpace::empty(); + for p in reader::tagged_docs(doc, tag_type_param_def) { + let bd = + TyDecoder::with_doc(tcx, cdata.cnum, p, + &mut |did| translate_def_id(cdata, did)) + .parse_type_param_def(); + types.push(bd.space, bd); + } + + let mut regions = subst::VecPerParamSpace::empty(); + for rp_doc in reader::tagged_docs(doc, tag_region_param_def) { + let ident_str_doc = reader::get_doc(rp_doc, + tag_region_param_def_ident); + let name = item_name(&*token::get_ident_interner(), ident_str_doc); + let def_id_doc = reader::get_doc(rp_doc, + tag_region_param_def_def_id); + let def_id = translated_def_id(cdata, def_id_doc); + + let doc = reader::get_doc(rp_doc, tag_region_param_def_space); + let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as usize); + + let doc = reader::get_doc(rp_doc, tag_region_param_def_index); + let index = reader::doc_as_u64(doc) as u32; + + let bounds = reader::tagged_docs(rp_doc, tag_items_data_region).map(|p| { + TyDecoder::with_doc(tcx, cdata.cnum, p, + &mut |did| translate_def_id(cdata, did)) + .parse_region() + }).collect(); + + regions.push(space, ty::RegionParameterDef { name: name, + def_id: def_id, + space: space, + index: index, + bounds: bounds }); + } + + ty::Generics { types: types, regions: regions } +} + +fn doc_predicate<'tcx>(cdata: Cmd, + doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>) + -> ty::Predicate<'tcx> +{ + let predicate_pos = cdata.xref_index.lookup( + cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize; + TyDecoder::new( + cdata.data(), cdata.cnum, predicate_pos, tcx, + &mut |did| translate_def_id(cdata, did) + ).parse_predicate() +} + +fn doc_predicates<'tcx>(base_doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>, + cdata: Cmd, + tag: usize) + -> ty::GenericPredicates<'tcx> +{ + let doc = reader::get_doc(base_doc, tag); + + let mut predicates = subst::VecPerParamSpace::empty(); + for predicate_doc in reader::tagged_docs(doc, tag_type_predicate) { + predicates.push(subst::TypeSpace, + doc_predicate(cdata, predicate_doc, tcx)); + } + for predicate_doc in reader::tagged_docs(doc, tag_self_predicate) { + predicates.push(subst::SelfSpace, + doc_predicate(cdata, predicate_doc, tcx)); + } + for predicate_doc in reader::tagged_docs(doc, tag_fn_predicate) { + predicates.push(subst::FnSpace, + doc_predicate(cdata, predicate_doc, tcx)); + } + + ty::GenericPredicates { predicates: predicates } +} + +pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool { + let trait_doc = cdata.lookup_item(trait_id); + assert!(item_family(trait_doc) == Family::Trait); + let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait); + reader::doc_as_u8(defaulted_doc) != 0 +} + +pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool { + let impl_doc = cdata.lookup_item(impl_id); + item_family(impl_doc) == Family::DefaultImpl +} + +pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { + let crate_doc = rbml::Doc::new(metadata); + let cm_doc = reader::get_doc(crate_doc, tag_codemap); + + reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| { + let mut decoder = reader::Decoder::new(filemap_doc); + Decodable::decode(&mut decoder).unwrap() + }).collect() +} + +pub fn is_extern_fn(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) -> bool { + let item_doc = match cdata.get_item(id) { + Some(doc) => doc, + None => return false, + }; + if let Fn = item_family(item_doc) { + let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx); + generics.types.is_empty() && match ty.sty { + ty::TyBareFn(_, fn_ty) => fn_ty.abi != abi::Rust, + _ => false, + } + } else { + false + } +} + +pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { + let closure_doc = cdata.lookup_item(closure_id); + let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind); + let mut decoder = reader::Decoder::new(closure_kind_doc); + ty::ClosureKind::decode(&mut decoder).unwrap() +} + +pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &ty::ctxt<'tcx>) + -> ty::ClosureTy<'tcx> { + let closure_doc = cdata.lookup_item(closure_id); + let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty); + TyDecoder::with_doc(tcx, cdata.cnum, closure_ty_doc, &mut |did| translate_def_id(cdata, did)) + .parse_closure_ty() +} + +fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey { + match reader::maybe_get_doc(item_doc, tag_def_key) { + Some(def_key_doc) => { + let mut decoder = reader::Decoder::new(def_key_doc); + hir_map::DefKey::decode(&mut decoder).unwrap() + } + None => { + panic!("failed to find block with tag {:?} for item with family {:?}", + tag_def_key, + item_family(item_doc)) + } + } +} + +pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath { + debug!("def_path(id={:?})", id); + hir_map::definitions::make_def_path(id, |parent| { + debug!("def_path: parent={:?}", parent); + let parent_doc = cdata.lookup_item(parent); + def_key(parent_doc) + }) +} diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs new file mode 100644 index 00000000000..2340efd2cae --- /dev/null +++ b/src/librustc_metadata/diagnostics.rs @@ -0,0 +1,77 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_snake_case)] + +register_long_diagnostics! { +E0454: r##" +A link name was given with an empty name. Erroneous code example: + +``` +#[link(name = "")] extern {} // error: #[link(name = "")] given with empty name +``` + +The rust compiler cannot link to an external library if you don't give it its +name. Example: + +``` +#[link(name = "some_lib")] extern {} // ok! +``` +"##, + +E0458: r##" +An unknown "kind" was specified for a link attribute. Erroneous code example: + +``` +#[link(kind = "wonderful_unicorn")] extern {} +// error: unknown kind: `wonderful_unicorn` +``` + +Please specify a valid "kind" value, from one of the following: + * static + * dylib + * framework +"##, + +E0459: r##" +A link was used without a name parameter. Erroneous code example: + +``` +#[link(kind = "dylib")] extern {} +// error: #[link(...)] specified without `name = "foo"` +``` + +Please add the name parameter to allow the rust compiler to find the library +you want. Example: + +``` +#[link(kind = "dylib", name = "some_lib")] extern {} // ok! +``` +"##, + +} + +register_diagnostics! { + E0455, // native frameworks are only available on OSX targets + E0456, // plugin `..` is not available for triple `..` + E0457, // plugin `..` only found in rlib format, but must be available... + E0514, // metadata version mismatch + E0460, // found possibly newer version of crate `..` + E0461, // couldn't find crate `..` with expected target triple .. + E0462, // found staticlib `..` instead of rlib or dylib + E0463, // can't find crate for `..` + E0464, // multiple matching crates for `..` + E0465, // multiple .. candidates for `..` found + E0466, // bad macro import + E0467, // bad macro reexport + E0468, // an `extern crate` loading macros must be at the crate root + E0469, // imported macro not found + E0470, // reexported macro not found +} diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs new file mode 100644 index 00000000000..1d88fa4454b --- /dev/null +++ b/src/librustc_metadata/encoder.rs @@ -0,0 +1,2078 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Metadata encoding + +#![allow(unused_must_use)] // everything is just a MemWriter, can't fail +#![allow(non_camel_case_types)] + +use common::*; +use cstore; +use decoder; +use tyencode; +use index::{self, IndexData}; + +use middle::cstore::{LOCAL_CRATE, CrateStore, InlinedItemRef, LinkMeta}; +use middle::def; +use middle::def_id::{CRATE_DEF_INDEX, DefId}; +use middle::dependency_format::Linkage; +use middle::stability; +use middle::subst; +use middle::ty::{self, Ty}; + +use rustc::back::svh::Svh; +use rustc::front::map::{LinkedPath, PathElem, PathElems}; +use rustc::front::map as ast_map; +use rustc::session::config; +use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; + +use serialize::Encodable; +use std::cell::RefCell; +use std::io::prelude::*; +use std::io::{Cursor, SeekFrom}; +use std::rc::Rc; +use std::u32; +use syntax::abi; +use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; +use syntax::attr; +use syntax::attr::AttrMetaMethods; +use syntax::diagnostic::SpanHandler; +use syntax::parse::token::special_idents; +use syntax; +use rbml::writer::Encoder; + +use rustc_front::hir; +use rustc_front::intravisit::Visitor; +use rustc_front::intravisit; + +pub type EncodeInlinedItem<'a> = + Box; + +pub struct EncodeParams<'a, 'tcx: 'a> { + pub diag: &'a SpanHandler, + pub tcx: &'a ty::ctxt<'tcx>, + pub reexports: &'a def::ExportMap, + pub item_symbols: &'a RefCell>, + pub link_meta: &'a LinkMeta, + pub cstore: &'a cstore::CStore, + pub encode_inlined_item: EncodeInlinedItem<'a>, + pub reachable: &'a NodeSet, +} + +pub struct EncodeContext<'a, 'tcx: 'a> { + pub diag: &'a SpanHandler, + pub tcx: &'a ty::ctxt<'tcx>, + pub reexports: &'a def::ExportMap, + pub item_symbols: &'a RefCell>, + pub link_meta: &'a LinkMeta, + pub cstore: &'a cstore::CStore, + pub encode_inlined_item: RefCell>, + pub type_abbrevs: tyencode::abbrev_map<'tcx>, + pub reachable: &'a NodeSet, +} + +impl<'a, 'tcx> EncodeContext<'a,'tcx> { + fn local_id(&self, def_id: DefId) -> NodeId { + self.tcx.map.as_local_node_id(def_id).unwrap() + } +} + +/// "interned" entries referenced by id +#[derive(PartialEq, Eq, Hash)] +pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } + +struct CrateIndex<'tcx> { + items: IndexData, + xrefs: FnvHashMap, u32>, // sequentially-assigned +} + +impl<'tcx> CrateIndex<'tcx> { + fn record(&mut self, id: DefId, rbml_w: &mut Encoder) { + let position = rbml_w.mark_stable_position(); + self.items.record(id, position); + } + + fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { + let old_len = self.xrefs.len() as u32; + *self.xrefs.entry(xref).or_insert(old_len) + } +} + +fn encode_name(rbml_w: &mut Encoder, name: Name) { + rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str()); +} + +fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { + rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id)); +} + +/// For every DefId that we create a metadata item for, we include a +/// serialized copy of its DefKey, which allows us to recreate a path. +fn encode_def_id_and_key(ecx: &EncodeContext, + rbml_w: &mut Encoder, + def_id: DefId) +{ + encode_def_id(rbml_w, def_id); + encode_def_key(ecx, rbml_w, def_id); +} + +fn encode_def_key(ecx: &EncodeContext, + rbml_w: &mut Encoder, + def_id: DefId) +{ + rbml_w.start_tag(tag_def_key); + let def_key = ecx.tcx.map.def_key(def_id); + def_key.encode(rbml_w); + rbml_w.end_tag(); +} + +fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + trait_ref: ty::TraitRef<'tcx>, + tag: usize) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + + rbml_w.start_tag(tag); + tyencode::enc_trait_ref(rbml_w, ty_str_ctxt, trait_ref); + rbml_w.end_tag(); +} + +// Item info table encoding +fn encode_family(rbml_w: &mut Encoder, c: char) { + rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8); +} + +pub fn def_to_u64(did: DefId) -> u64 { + assert!(did.index.as_u32() < u32::MAX); + (did.krate as u64) << 32 | (did.index.as_usize() as u64) +} + +pub fn def_to_string(did: DefId) -> String { + format!("{}:{}", did.krate, did.index.as_usize()) +} + +fn encode_item_variances(rbml_w: &mut Encoder, + ecx: &EncodeContext, + id: NodeId) { + let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id)); + rbml_w.start_tag(tag_item_variances); + v.encode(rbml_w); + rbml_w.end_tag(); +} + +fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>, + id: NodeId) { + encode_bounds_and_type(rbml_w, + ecx, + index, + &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)), + &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id))); +} + +fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>, + scheme: &ty::TypeScheme<'tcx>, + predicates: &ty::GenericPredicates<'tcx>) { + encode_generics(rbml_w, ecx, index, + &scheme.generics, &predicates, tag_item_generics); + encode_type(ecx, rbml_w, scheme.ty); +} + +fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) { + let id = def_to_u64(vid); + rbml_w.wr_tagged_u64(tag_items_data_item_variant, id); + rbml_w.wr_tagged_u64(tag_mod_child, id); +} + +pub fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + closure_type: &ty::ClosureTy<'tcx>) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + tyencode::enc_closure_ty(rbml_w, ty_str_ctxt, closure_type); +} + +pub fn write_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + typ: Ty<'tcx>) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + tyencode::enc_ty(rbml_w, ty_str_ctxt, typ); +} + +pub fn write_trait_ref<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + trait_ref: &ty::TraitRef<'tcx>) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + tyencode::enc_trait_ref(rbml_w, ty_str_ctxt, *trait_ref); +} + +pub fn write_region(ecx: &EncodeContext, + rbml_w: &mut Encoder, + r: ty::Region) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + tyencode::enc_region(rbml_w, ty_str_ctxt, r); +} + +fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + typ: Ty<'tcx>) { + rbml_w.start_tag(tag_items_data_item_type); + write_type(ecx, rbml_w, typ); + rbml_w.end_tag(); +} + +fn encode_region(ecx: &EncodeContext, + rbml_w: &mut Encoder, + r: ty::Region) { + rbml_w.start_tag(tag_items_data_region); + write_region(ecx, rbml_w, r); + rbml_w.end_tag(); +} + +fn encode_symbol(ecx: &EncodeContext, + rbml_w: &mut Encoder, + id: NodeId) { + match ecx.item_symbols.borrow().get(&id) { + Some(x) => { + debug!("encode_symbol(id={}, str={})", id, *x); + rbml_w.wr_tagged_str(tag_items_data_item_symbol, x); + } + None => { + ecx.diag.handler().bug( + &format!("encode_symbol: id not found {}", id)); + } + } +} + +fn encode_disr_val(_: &EncodeContext, + rbml_w: &mut Encoder, + disr_val: ty::Disr) { + rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_string()); +} + +fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { + rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); +} + +fn encode_struct_fields(rbml_w: &mut Encoder, + variant: ty::VariantDef) { + for f in &variant.fields { + if f.name == special_idents::unnamed_field.name { + rbml_w.start_tag(tag_item_unnamed_field); + } else { + rbml_w.start_tag(tag_item_field); + encode_name(rbml_w, f.name); + } + encode_struct_field_family(rbml_w, f.vis); + encode_def_id(rbml_w, f.did); + rbml_w.end_tag(); + } +} + +fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + id: NodeId, + vis: hir::Visibility, + index: &mut CrateIndex<'tcx>) { + debug!("encode_enum_variant_info(id={})", id); + + let mut disr_val = 0; + let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id)); + for variant in &def.variants { + let vid = variant.did; + let variant_node_id = ecx.local_id(vid); + + if let ty::VariantKind::Struct = variant.kind() { + // tuple-like enum variant fields aren't really items so + // don't try to encode them. + for field in &variant.fields { + encode_field(ecx, rbml_w, field, index); + } + } + + index.record(vid, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, vid); + encode_family(rbml_w, match variant.kind() { + ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v', + ty::VariantKind::Struct => 'V' + }); + encode_name(rbml_w, variant.name); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id)); + encode_visibility(rbml_w, vis); + + let attrs = ecx.tcx.get_attrs(vid); + encode_attributes(rbml_w, &attrs); + encode_repr_attrs(rbml_w, ecx, &attrs); + + let stab = stability::lookup(ecx.tcx, vid); + encode_stability(rbml_w, stab); + + encode_struct_fields(rbml_w, variant); + + let specified_disr_val = variant.disr_val; + if specified_disr_val != disr_val { + encode_disr_val(ecx, rbml_w, specified_disr_val); + disr_val = specified_disr_val; + } + encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id); + + ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path)); + rbml_w.end_tag(); + disr_val = disr_val.wrapping_add(1); + } +} + +fn encode_path>(rbml_w: &mut Encoder, path: PI) { + let path = path.collect::>(); + rbml_w.start_tag(tag_path); + rbml_w.wr_tagged_u32(tag_path_len, path.len() as u32); + for pe in &path { + let tag = match *pe { + ast_map::PathMod(_) => tag_path_elem_mod, + ast_map::PathName(_) => tag_path_elem_name + }; + rbml_w.wr_tagged_str(tag, &pe.name().as_str()); + } + rbml_w.end_tag(); +} + +/// Iterates through "auxiliary node IDs", which are node IDs that describe +/// top-level items that are sub-items of the given item. Specifically: +/// +/// * For newtype structs, iterates through the node ID of the constructor. +fn each_auxiliary_node_id(item: &hir::Item, callback: F) -> bool where + F: FnOnce(NodeId) -> bool, +{ + let mut continue_ = true; + match item.node { + hir::ItemStruct(ref struct_def, _) => { + // If this is a newtype struct, return the constructor. + if struct_def.is_tuple() { + continue_ = callback(struct_def.id()); + } + } + _ => {} + } + + continue_ +} + +fn encode_reexports(ecx: &EncodeContext, + rbml_w: &mut Encoder, + id: NodeId) { + debug!("(encoding info for module) encoding reexports for {}", id); + match ecx.reexports.get(&id) { + Some(exports) => { + debug!("(encoding info for module) found reexports for {}", id); + for exp in exports { + debug!("(encoding info for module) reexport '{}' ({:?}) for \ + {}", + exp.name, + exp.def_id, + id); + rbml_w.start_tag(tag_items_data_item_reexport); + rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, + def_to_u64(exp.def_id)); + rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, + &exp.name.as_str()); + rbml_w.end_tag(); + } + }, + None => debug!("(encoding info for module) found no reexports for {}", id), + } +} + +fn encode_info_for_mod(ecx: &EncodeContext, + rbml_w: &mut Encoder, + md: &hir::Mod, + attrs: &[ast::Attribute], + id: NodeId, + path: PathElems, + name: Name, + vis: hir::Visibility) { + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id)); + encode_family(rbml_w, 'm'); + encode_name(rbml_w, name); + debug!("(encoding info for module) encoding info for module ID {}", id); + + // Encode info about all the module children. + for item_id in &md.item_ids { + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); + + let item = ecx.tcx.map.expect_item(item_id.id); + each_auxiliary_node_id(item, |auxiliary_node_id| { + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); + true + }); + } + + encode_path(rbml_w, path.clone()); + encode_visibility(rbml_w, vis); + + let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(id)); + encode_stability(rbml_w, stab); + + // Encode the reexports of this module, if this module is public. + if vis == hir::Public { + debug!("(encoding info for module) encoding reexports for {}", id); + encode_reexports(ecx, rbml_w, id); + } + encode_attributes(rbml_w, attrs); + + rbml_w.end_tag(); +} + +fn encode_struct_field_family(rbml_w: &mut Encoder, + visibility: hir::Visibility) { + encode_family(rbml_w, match visibility { + hir::Public => 'g', + hir::Inherited => 'N' + }); +} + +fn encode_visibility(rbml_w: &mut Encoder, visibility: hir::Visibility) { + let ch = match visibility { + hir::Public => 'y', + hir::Inherited => 'i', + }; + rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); +} + +fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) { + rbml_w.start_tag(tag_items_data_item_constness); + let ch = match constness { + hir::Constness::Const => 'c', + hir::Constness::NotConst => 'n', + }; + rbml_w.wr_str(&ch.to_string()); + rbml_w.end_tag(); +} + +fn encode_explicit_self(rbml_w: &mut Encoder, + explicit_self: &ty::ExplicitSelfCategory) { + let tag = tag_item_trait_method_explicit_self; + + // Encode the base self type. + match *explicit_self { + ty::StaticExplicitSelfCategory => { + rbml_w.wr_tagged_bytes(tag, &['s' as u8]); + } + ty::ByValueExplicitSelfCategory => { + rbml_w.wr_tagged_bytes(tag, &['v' as u8]); + } + ty::ByBoxExplicitSelfCategory => { + rbml_w.wr_tagged_bytes(tag, &['~' as u8]); + } + ty::ByReferenceExplicitSelfCategory(_, m) => { + // FIXME(#4846) encode custom lifetime + let ch = encode_mutability(m); + rbml_w.wr_tagged_bytes(tag, &['&' as u8, ch]); + } + } + + fn encode_mutability(m: hir::Mutability) -> u8 { + match m { + hir::MutImmutable => 'i' as u8, + hir::MutMutable => 'm' as u8, + } + } +} + +fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { + rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8); +} + +fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + field: ty::FieldDef<'tcx>, + index: &mut CrateIndex<'tcx>) { + let nm = field.name; + let id = ecx.local_id(field.did); + + index.record(field.did, rbml_w); + rbml_w.start_tag(tag_items_data_item); + debug!("encode_field: encoding {} {}", nm, id); + encode_struct_field_family(rbml_w, field.vis); + encode_name(rbml_w, nm); + encode_bounds_and_type_for_item(rbml_w, ecx, index, id); + encode_def_id_and_key(ecx, rbml_w, field.did); + + let stab = stability::lookup(ecx.tcx, field.did); + encode_stability(rbml_w, stab); + + rbml_w.end_tag(); +} + +fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + name: Name, + ctor_id: NodeId, + index: &mut CrateIndex<'tcx>, + struct_id: NodeId) { + let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); + + index.record(ctor_def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, ctor_def_id); + encode_family(rbml_w, 'o'); + encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id); + encode_name(rbml_w, name); + ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path)); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); + + if ecx.item_symbols.borrow().contains_key(&ctor_id) { + encode_symbol(ecx, rbml_w, ctor_id); + } + + let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(ctor_id)); + encode_stability(rbml_w, stab); + + // indicate that this is a tuple struct ctor, because downstream users will normally want + // the tuple struct definition, but without this there is no way for them to tell that + // they actually have a ctor rather than a normal function + rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); + + rbml_w.end_tag(); +} + +fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>, + generics: &ty::Generics<'tcx>, + predicates: &ty::GenericPredicates<'tcx>, + tag: usize) +{ + rbml_w.start_tag(tag); + + // Type parameters + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + + for param in &generics.types { + rbml_w.start_tag(tag_type_param_def); + tyencode::enc_type_param_def(rbml_w, ty_str_ctxt, param); + rbml_w.end_tag(); + } + + // Region parameters + for param in &generics.regions { + rbml_w.start_tag(tag_region_param_def); + + rbml_w.start_tag(tag_region_param_def_ident); + encode_name(rbml_w, param.name); + rbml_w.end_tag(); + + rbml_w.wr_tagged_u64(tag_region_param_def_def_id, + def_to_u64(param.def_id)); + + rbml_w.wr_tagged_u64(tag_region_param_def_space, + param.space.to_uint() as u64); + + rbml_w.wr_tagged_u64(tag_region_param_def_index, + param.index as u64); + + for &bound_region in ¶m.bounds { + encode_region(ecx, rbml_w, bound_region); + } + + rbml_w.end_tag(); + } + + encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); + + rbml_w.end_tag(); +} + +fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, + _ecx: &EncodeContext<'a,'tcx>, + index: &mut CrateIndex<'tcx>, + predicates: &ty::GenericPredicates<'tcx>) +{ + for (space, _, predicate) in predicates.predicates.iter_enumerated() { + let tag = match space { + subst::TypeSpace => tag_type_predicate, + subst::SelfSpace => tag_self_predicate, + subst::FnSpace => tag_fn_predicate + }; + + rbml_w.wr_tagged_u32(tag, + index.add_xref(XRef::Predicate(predicate.clone()))); + } +} + +fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, + ecx: &EncodeContext<'a,'tcx>, + index: &mut CrateIndex<'tcx>, + predicates: &ty::GenericPredicates<'tcx>, + tag: usize) +{ + rbml_w.start_tag(tag); + encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); + rbml_w.end_tag(); +} + +fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + index: &mut CrateIndex<'tcx>, + method_ty: &ty::Method<'tcx>) { + encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); + encode_name(rbml_w, method_ty.name); + encode_generics(rbml_w, ecx, index, + &method_ty.generics, &method_ty.predicates, + tag_method_ty_generics); + encode_visibility(rbml_w, method_ty.vis); + encode_explicit_self(rbml_w, &method_ty.explicit_self); + match method_ty.explicit_self { + ty::StaticExplicitSelfCategory => { + encode_family(rbml_w, STATIC_METHOD_FAMILY); + } + _ => encode_family(rbml_w, METHOD_FAMILY) + } +} + +fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + index: &mut CrateIndex<'tcx>, + associated_const: &ty::AssociatedConst, + impl_path: PathElems, + parent_id: NodeId, + impl_item_opt: Option<&hir::ImplItem>) { + debug!("encode_info_for_associated_const({:?},{:?})", + associated_const.def_id, + associated_const.name); + + index.record(associated_const.def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + + encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); + encode_name(rbml_w, associated_const.name); + encode_visibility(rbml_w, associated_const.vis); + encode_family(rbml_w, 'C'); + + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 'C'); + + encode_bounds_and_type_for_item(rbml_w, ecx, index, + ecx.local_id(associated_const.def_id)); + + let stab = stability::lookup(ecx.tcx, associated_const.def_id); + encode_stability(rbml_w, stab); + + let elem = ast_map::PathName(associated_const.name); + encode_path(rbml_w, impl_path.chain(Some(elem))); + + if let Some(ii) = impl_item_opt { + encode_attributes(rbml_w, &ii.attrs); + encode_inlined_item(ecx, + rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + ii)); + } + + rbml_w.end_tag(); +} + +fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + index: &mut CrateIndex<'tcx>, + m: &ty::Method<'tcx>, + impl_path: PathElems, + is_default_impl: bool, + parent_id: NodeId, + impl_item_opt: Option<&hir::ImplItem>) { + + debug!("encode_info_for_method: {:?} {:?}", m.def_id, + m.name); + index.record(m.def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + + encode_method_ty_fields(ecx, rbml_w, index, m); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 'r'); + + let stab = stability::lookup(ecx.tcx, m.def_id); + encode_stability(rbml_w, stab); + + let m_node_id = ecx.local_id(m.def_id); + encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id); + + let elem = ast_map::PathName(m.name); + encode_path(rbml_w, impl_path.chain(Some(elem))); + if let Some(impl_item) = impl_item_opt { + if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { + encode_attributes(rbml_w, &impl_item.attrs); + let scheme = ecx.tcx.lookup_item_type(m.def_id); + let any_types = !scheme.generics.types.is_empty(); + let needs_inline = any_types || is_default_impl || + attr::requests_inline(&impl_item.attrs); + if needs_inline || sig.constness == hir::Constness::Const { + encode_inlined_item(ecx, + rbml_w, + InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + impl_item)); + } + encode_constness(rbml_w, sig.constness); + if !any_types { + let m_id = ecx.local_id(m.def_id); + encode_symbol(ecx, rbml_w, m_id); + } + encode_method_argument_names(rbml_w, &sig.decl); + } + } + + rbml_w.end_tag(); +} + +fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + index: &mut CrateIndex<'tcx>, + associated_type: &ty::AssociatedType<'tcx>, + impl_path: PathElems, + parent_id: NodeId, + impl_item_opt: Option<&hir::ImplItem>) { + debug!("encode_info_for_associated_type({:?},{:?})", + associated_type.def_id, + associated_type.name); + + index.record(associated_type.def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + + encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); + encode_name(rbml_w, associated_type.name); + encode_visibility(rbml_w, associated_type.vis); + encode_family(rbml_w, 'y'); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); + encode_item_sort(rbml_w, 't'); + + let stab = stability::lookup(ecx.tcx, associated_type.def_id); + encode_stability(rbml_w, stab); + + let elem = ast_map::PathName(associated_type.name); + encode_path(rbml_w, impl_path.chain(Some(elem))); + + if let Some(ii) = impl_item_opt { + encode_attributes(rbml_w, &ii.attrs); + } else { + encode_predicates(rbml_w, ecx, index, + &ecx.tcx.lookup_predicates(associated_type.def_id), + tag_item_generics); + } + + if let Some(ty) = associated_type.ty { + encode_type(ecx, rbml_w, ty); + } + + rbml_w.end_tag(); +} + +fn encode_method_argument_names(rbml_w: &mut Encoder, + decl: &hir::FnDecl) { + rbml_w.start_tag(tag_method_argument_names); + for arg in &decl.inputs { + let tag = tag_method_argument_name; + if let hir::PatIdent(_, ref path1, _) = arg.pat.node { + let name = path1.node.name.as_str(); + rbml_w.wr_tagged_bytes(tag, name.as_bytes()); + } else { + rbml_w.wr_tagged_bytes(tag, &[]); + } + } + rbml_w.end_tag(); +} + +fn encode_repr_attrs(rbml_w: &mut Encoder, + ecx: &EncodeContext, + attrs: &[ast::Attribute]) { + let mut repr_attrs = Vec::new(); + for attr in attrs { + repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(), + attr)); + } + rbml_w.start_tag(tag_items_data_item_repr); + repr_attrs.encode(rbml_w); + rbml_w.end_tag(); +} + +fn encode_inlined_item(ecx: &EncodeContext, + rbml_w: &mut Encoder, + ii: InlinedItemRef) { + let mut eii = ecx.encode_inlined_item.borrow_mut(); + let eii: &mut EncodeInlinedItem = &mut *eii; + eii(ecx, rbml_w, ii) +} + +const FN_FAMILY: char = 'f'; +const STATIC_METHOD_FAMILY: char = 'F'; +const METHOD_FAMILY: char = 'h'; + +// Encodes the inherent implementations of a structure, enumeration, or trait. +fn encode_inherent_implementations(ecx: &EncodeContext, + rbml_w: &mut Encoder, + def_id: DefId) { + match ecx.tcx.inherent_impls.borrow().get(&def_id) { + None => {} + Some(implementations) => { + for &impl_def_id in implementations.iter() { + rbml_w.start_tag(tag_items_data_item_inherent_impl); + encode_def_id(rbml_w, impl_def_id); + rbml_w.end_tag(); + } + } + } +} + +fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) { + stab_opt.map(|stab| { + rbml_w.start_tag(tag_items_data_item_stability); + stab.encode(rbml_w).unwrap(); + rbml_w.end_tag(); + }); +} + +fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + xrefs: FnvHashMap, u32>) +{ + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + + let mut xref_positions = vec![0; xrefs.len()]; + rbml_w.start_tag(tag_xref_data); + for (xref, id) in xrefs.into_iter() { + xref_positions[id as usize] = rbml_w.mark_stable_position() as u32; + match xref { + XRef::Predicate(p) => { + tyencode::enc_predicate(rbml_w, ty_str_ctxt, &p) + } + } + } + rbml_w.end_tag(); + + rbml_w.start_tag(tag_xref_index); + index::write_dense_index(xref_positions, rbml_w.writer); + rbml_w.end_tag(); +} + +fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + item: &hir::Item, + index: &mut CrateIndex<'tcx>, + path: PathElems, + vis: hir::Visibility) { + let tcx = ecx.tcx; + + debug!("encoding info for item at {}", + tcx.sess.codemap().span_to_string(item.span)); + + let def_id = ecx.tcx.map.local_def_id(item.id); + let stab = stability::lookup(tcx, ecx.tcx.map.local_def_id(item.id)); + + match item.node { + hir::ItemStatic(_, m, _) => { + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + if m == hir::MutMutable { + encode_family(rbml_w, 'b'); + } else { + encode_family(rbml_w, 'c'); + } + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_symbol(ecx, rbml_w, item.id); + encode_name(rbml_w, item.name); + encode_path(rbml_w, path); + encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_attributes(rbml_w, &item.attrs); + rbml_w.end_tag(); + } + hir::ItemConst(_, _) => { + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'C'); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); + encode_path(rbml_w, path); + encode_attributes(rbml_w, &item.attrs); + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); + encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + rbml_w.end_tag(); + } + hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, FN_FAMILY); + let tps_len = generics.ty_params.len(); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); + encode_path(rbml_w, path); + encode_attributes(rbml_w, &item.attrs); + let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); + if needs_inline || constness == hir::Constness::Const { + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); + } + if tps_len == 0 { + encode_symbol(ecx, rbml_w, item.id); + } + encode_constness(rbml_w, constness); + encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + encode_method_argument_names(rbml_w, &**decl); + rbml_w.end_tag(); + } + hir::ItemMod(ref m) => { + index.record(def_id, rbml_w); + encode_info_for_mod(ecx, + rbml_w, + m, + &item.attrs, + item.id, + path, + item.name, + item.vis); + } + hir::ItemForeignMod(ref fm) => { + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'n'); + encode_name(rbml_w, item.name); + encode_path(rbml_w, path); + + // Encode all the items in this module. + for foreign_item in &fm.items { + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); + } + encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + rbml_w.end_tag(); + } + hir::ItemTy(..) => { + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'y'); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); + encode_path(rbml_w, path); + encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + rbml_w.end_tag(); + } + hir::ItemEnum(ref enum_definition, _) => { + index.record(def_id, rbml_w); + + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 't'); + encode_item_variances(rbml_w, ecx, item.id); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_repr_attrs(rbml_w, ecx, &item.attrs); + for v in &enum_definition.variants { + encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); + } + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); + encode_path(rbml_w, path); + + // Encode inherent implementations for this enumeration. + encode_inherent_implementations(ecx, rbml_w, def_id); + + encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + rbml_w.end_tag(); + + encode_enum_variant_info(ecx, + rbml_w, + item.id, + vis, + index); + } + hir::ItemStruct(ref struct_def, _) => { + let def = ecx.tcx.lookup_adt_def(def_id); + let variant = def.struct_variant(); + + /* Index the class*/ + index.record(def_id, rbml_w); + + /* Now, make an item for the class itself */ + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'S'); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + + encode_item_variances(rbml_w, ecx, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_path(rbml_w, path.clone()); + encode_stability(rbml_w, stab); + encode_visibility(rbml_w, vis); + encode_repr_attrs(rbml_w, ecx, &item.attrs); + + /* Encode def_ids for each field and method + for methods, write all the stuff get_trait_method + needs to know*/ + encode_struct_fields(rbml_w, variant); + + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); + + // Encode inherent implementations for this structure. + encode_inherent_implementations(ecx, rbml_w, def_id); + + if !struct_def.is_struct() { + let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); + rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, + def_to_u64(ctor_did)); + } + + rbml_w.end_tag(); + + for field in &variant.fields { + encode_field(ecx, rbml_w, field, index); + } + + // If this is a tuple-like struct, encode the type of the constructor. + if !struct_def.is_struct() { + encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id); + } + } + hir::ItemDefaultImpl(unsafety, _) => { + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'd'); + encode_name(rbml_w, item.name); + encode_unsafety(rbml_w, unsafety); + + let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); + encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); + rbml_w.end_tag(); + } + hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { + // We need to encode information about the default methods we + // have inherited, so we drive this based on the impl structure. + let impl_items = tcx.impl_items.borrow(); + let items = impl_items.get(&def_id).unwrap(); + + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'i'); + encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_unsafety(rbml_w, unsafety); + encode_polarity(rbml_w, polarity); + + match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) { + Some(&kind) => { + rbml_w.start_tag(tag_impl_coerce_unsized_kind); + kind.encode(rbml_w); + rbml_w.end_tag(); + } + None => {} + } + + for &item_def_id in items { + rbml_w.start_tag(tag_item_impl_item); + match item_def_id { + ty::ConstTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 'C'); + } + ty::MethodTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 'r'); + } + ty::TypeTraitItemId(item_def_id) => { + encode_def_id(rbml_w, item_def_id); + encode_item_sort(rbml_w, 't'); + } + } + rbml_w.end_tag(); + } + if let Some(trait_ref) = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)) { + encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref); + } + encode_path(rbml_w, path.clone()); + encode_stability(rbml_w, stab); + rbml_w.end_tag(); + + // Iterate down the trait items, emitting them. We rely on the + // assumption that all of the actually implemented trait items + // appear first in the impl structure, in the same order they do + // in the ast. This is a little sketchy. + let num_implemented_methods = ast_items.len(); + for (i, &trait_item_def_id) in items.iter().enumerate() { + let ast_item = if i < num_implemented_methods { + Some(&*ast_items[i]) + } else { + None + }; + + match tcx.impl_or_trait_item(trait_item_def_id.def_id()) { + ty::ConstTraitItem(ref associated_const) => { + encode_info_for_associated_const(ecx, + rbml_w, + index, + &*associated_const, + path.clone(), + item.id, + ast_item) + } + ty::MethodTraitItem(ref method_type) => { + encode_info_for_method(ecx, + rbml_w, + index, + &**method_type, + path.clone(), + false, + item.id, + ast_item) + } + ty::TypeTraitItem(ref associated_type) => { + encode_info_for_associated_type(ecx, + rbml_w, + index, + &**associated_type, + path.clone(), + item.id, + ast_item) + } + } + } + } + hir::ItemTrait(_, _, _, ref ms) => { + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_family(rbml_w, 'I'); + encode_item_variances(rbml_w, ecx, item.id); + let trait_def = tcx.lookup_trait_def(def_id); + let trait_predicates = tcx.lookup_predicates(def_id); + encode_unsafety(rbml_w, trait_def.unsafety); + encode_paren_sugar(rbml_w, trait_def.paren_sugar); + encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id)); + encode_associated_type_names(rbml_w, &trait_def.associated_type_names); + encode_generics(rbml_w, ecx, index, + &trait_def.generics, &trait_predicates, + tag_item_generics); + encode_predicates(rbml_w, ecx, index, + &tcx.lookup_super_predicates(def_id), + tag_item_super_predicates); + encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); + encode_name(rbml_w, item.name); + encode_attributes(rbml_w, &item.attrs); + encode_visibility(rbml_w, vis); + encode_stability(rbml_w, stab); + for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { + rbml_w.start_tag(tag_item_trait_item); + match method_def_id { + ty::ConstTraitItemId(const_def_id) => { + encode_def_id(rbml_w, const_def_id); + encode_item_sort(rbml_w, 'C'); + } + ty::MethodTraitItemId(method_def_id) => { + encode_def_id(rbml_w, method_def_id); + encode_item_sort(rbml_w, 'r'); + } + ty::TypeTraitItemId(type_def_id) => { + encode_def_id(rbml_w, type_def_id); + encode_item_sort(rbml_w, 't'); + } + } + rbml_w.end_tag(); + + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(method_def_id.def_id())); + } + encode_path(rbml_w, path.clone()); + + // Encode inherent implementations for this trait. + encode_inherent_implementations(ecx, rbml_w, def_id); + + rbml_w.end_tag(); + + // Now output the trait item info for each trait item. + let r = tcx.trait_item_def_ids(def_id); + for (i, &item_def_id) in r.iter().enumerate() { + assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); + + index.record(item_def_id.def_id(), rbml_w); + rbml_w.start_tag(tag_items_data_item); + + encode_parent_item(rbml_w, def_id); + + let stab = stability::lookup(tcx, item_def_id.def_id()); + encode_stability(rbml_w, stab); + + let trait_item_type = + tcx.impl_or_trait_item(item_def_id.def_id()); + let is_nonstatic_method; + match trait_item_type { + ty::ConstTraitItem(associated_const) => { + encode_name(rbml_w, associated_const.name); + encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); + encode_visibility(rbml_w, associated_const.vis); + + let elem = ast_map::PathName(associated_const.name); + encode_path(rbml_w, + path.clone().chain(Some(elem))); + + encode_family(rbml_w, 'C'); + + encode_bounds_and_type_for_item(rbml_w, ecx, index, + ecx.local_id(associated_const.def_id)); + + is_nonstatic_method = false; + } + ty::MethodTraitItem(method_ty) => { + let method_def_id = item_def_id.def_id(); + + encode_method_ty_fields(ecx, rbml_w, index, &*method_ty); + + let elem = ast_map::PathName(method_ty.name); + encode_path(rbml_w, + path.clone().chain(Some(elem))); + + match method_ty.explicit_self { + ty::StaticExplicitSelfCategory => { + encode_family(rbml_w, + STATIC_METHOD_FAMILY); + } + _ => { + encode_family(rbml_w, + METHOD_FAMILY); + } + } + encode_bounds_and_type_for_item(rbml_w, ecx, index, + ecx.local_id(method_def_id)); + + is_nonstatic_method = method_ty.explicit_self != + ty::StaticExplicitSelfCategory; + } + ty::TypeTraitItem(associated_type) => { + encode_name(rbml_w, associated_type.name); + encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); + + let elem = ast_map::PathName(associated_type.name); + encode_path(rbml_w, + path.clone().chain(Some(elem))); + + encode_item_sort(rbml_w, 't'); + encode_family(rbml_w, 'y'); + + if let Some(ty) = associated_type.ty { + encode_type(ecx, rbml_w, ty); + } + + is_nonstatic_method = false; + } + } + + let trait_item = &*ms[i]; + encode_attributes(rbml_w, &trait_item.attrs); + match trait_item.node { + hir::ConstTraitItem(_, ref default) => { + if default.is_some() { + encode_item_sort(rbml_w, 'C'); + } else { + encode_item_sort(rbml_w, 'c'); + } + + encode_inlined_item(ecx, rbml_w, + InlinedItemRef::TraitItem(def_id, trait_item)); + } + hir::MethodTraitItem(ref sig, ref body) => { + // If this is a static method, we've already + // encoded this. + if is_nonstatic_method { + // FIXME: I feel like there is something funny + // going on. + encode_bounds_and_type_for_item(rbml_w, ecx, index, + ecx.local_id(item_def_id.def_id())); + } + + if body.is_some() { + encode_item_sort(rbml_w, 'p'); + encode_inlined_item(ecx, rbml_w, + InlinedItemRef::TraitItem(def_id, trait_item)); + } else { + encode_item_sort(rbml_w, 'r'); + } + encode_method_argument_names(rbml_w, &sig.decl); + } + + hir::TypeTraitItem(..) => {} + } + + rbml_w.end_tag(); + } + } + hir::ItemExternCrate(_) | hir::ItemUse(_) => { + // these are encoded separately + } + } +} + +fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + nitem: &hir::ForeignItem, + index: &mut CrateIndex<'tcx>, + path: PathElems, + abi: abi::Abi) { + let def_id = ecx.tcx.map.local_def_id(nitem.id); + + index.record(def_id, rbml_w); + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + encode_visibility(rbml_w, nitem.vis); + match nitem.node { + hir::ForeignItemFn(ref fndecl, _) => { + encode_family(rbml_w, FN_FAMILY); + encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); + encode_name(rbml_w, nitem.name); + if abi == abi::RustIntrinsic || abi == abi::PlatformIntrinsic { + encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem)); + } + encode_attributes(rbml_w, &*nitem.attrs); + let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); + encode_stability(rbml_w, stab); + encode_symbol(ecx, rbml_w, nitem.id); + encode_method_argument_names(rbml_w, &*fndecl); + } + hir::ForeignItemStatic(_, mutbl) => { + if mutbl { + encode_family(rbml_w, 'b'); + } else { + encode_family(rbml_w, 'c'); + } + encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); + encode_attributes(rbml_w, &*nitem.attrs); + let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); + encode_stability(rbml_w, stab); + encode_symbol(ecx, rbml_w, nitem.id); + encode_name(rbml_w, nitem.name); + } + } + encode_path(rbml_w, path); + rbml_w.end_tag(); +} + +fn my_visit_expr(expr: &hir::Expr, + rbml_w: &mut Encoder, + ecx: &EncodeContext, + index: &mut CrateIndex) { + match expr.node { + hir::ExprClosure(..) => { + let def_id = ecx.tcx.map.local_def_id(expr.id); + + index.record(def_id, rbml_w); + + rbml_w.start_tag(tag_items_data_item); + encode_def_id_and_key(ecx, rbml_w, def_id); + + rbml_w.start_tag(tag_items_closure_ty); + write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]); + rbml_w.end_tag(); + + rbml_w.start_tag(tag_items_closure_kind); + ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); + rbml_w.end_tag(); + + ecx.tcx.map.with_path(expr.id, |path| encode_path(rbml_w, path)); + + rbml_w.end_tag(); + } + _ => { } + } +} + +fn my_visit_item<'a, 'tcx>(i: &hir::Item, + rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>) { + ecx.tcx.map.with_path(i.id, |path| { + encode_info_for_item(ecx, rbml_w, i, index, path, i.vis); + }); +} + +fn my_visit_foreign_item<'a, 'tcx>(ni: &hir::ForeignItem, + rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + index: &mut CrateIndex<'tcx>) { + debug!("writing foreign item {}::{}", + ecx.tcx.map.path_to_string(ni.id), + ni.name); + + let abi = ecx.tcx.map.get_foreign_abi(ni.id); + ecx.tcx.map.with_path(ni.id, |path| { + encode_info_for_foreign_item(ecx, rbml_w, + ni, index, + path, abi); + }); +} + +struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { + rbml_w_for_visit_item: &'a mut Encoder<'b>, + ecx: &'a EncodeContext<'c,'tcx>, + index: &'a mut CrateIndex<'tcx>, +} + +impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { + fn visit_expr(&mut self, ex: &'tcx hir::Expr) { + intravisit::walk_expr(self, ex); + my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index); + } + fn visit_item(&mut self, i: &'tcx hir::Item) { + intravisit::walk_item(self, i); + my_visit_item(i, self.rbml_w_for_visit_item, self.ecx, self.index); + } + fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { + intravisit::walk_foreign_item(self, ni); + my_visit_foreign_item(ni, self.rbml_w_for_visit_item, self.ecx, self.index); + } +} + +fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder) + -> CrateIndex<'tcx> { + let krate = ecx.tcx.map.krate(); + + let mut index = CrateIndex { + items: IndexData::new(ecx.tcx.map.num_local_def_ids()), + xrefs: FnvHashMap() + }; + rbml_w.start_tag(tag_items_data); + + index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); + encode_info_for_mod(ecx, + rbml_w, + &krate.module, + &[], + CRATE_NODE_ID, + [].iter().cloned().chain(LinkedPath::empty()), + syntax::parse::token::intern(&ecx.link_meta.crate_name), + hir::Public); + + krate.visit_all_items(&mut EncodeVisitor { + index: &mut index, + ecx: ecx, + rbml_w_for_visit_item: &mut *rbml_w, + }); + + rbml_w.end_tag(); + index +} + +fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { + rbml_w.start_tag(tag_index); + index.write_index(rbml_w.writer); + rbml_w.end_tag(); +} + +fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) { + match mi.node { + ast::MetaWord(ref name) => { + rbml_w.start_tag(tag_meta_item_word); + rbml_w.wr_tagged_str(tag_meta_item_name, name); + rbml_w.end_tag(); + } + ast::MetaNameValue(ref name, ref value) => { + match value.node { + ast::LitStr(ref value, _) => { + rbml_w.start_tag(tag_meta_item_name_value); + rbml_w.wr_tagged_str(tag_meta_item_name, name); + rbml_w.wr_tagged_str(tag_meta_item_value, value); + rbml_w.end_tag(); + } + _ => {/* FIXME (#623): encode other variants */ } + } + } + ast::MetaList(ref name, ref items) => { + rbml_w.start_tag(tag_meta_item_list); + rbml_w.wr_tagged_str(tag_meta_item_name, name); + for inner_item in items { + encode_meta_item(rbml_w, &**inner_item); + } + rbml_w.end_tag(); + } + } +} + +fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { + rbml_w.start_tag(tag_attributes); + for attr in attrs { + rbml_w.start_tag(tag_attribute); + rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8); + encode_meta_item(rbml_w, &*attr.node.value); + rbml_w.end_tag(); + } + rbml_w.end_tag(); +} + +fn encode_unsafety(rbml_w: &mut Encoder, unsafety: hir::Unsafety) { + let byte: u8 = match unsafety { + hir::Unsafety::Normal => 0, + hir::Unsafety::Unsafe => 1, + }; + rbml_w.wr_tagged_u8(tag_unsafety, byte); +} + +fn encode_paren_sugar(rbml_w: &mut Encoder, paren_sugar: bool) { + let byte: u8 = if paren_sugar {1} else {0}; + rbml_w.wr_tagged_u8(tag_paren_sugar, byte); +} + +fn encode_defaulted(rbml_w: &mut Encoder, is_defaulted: bool) { + let byte: u8 = if is_defaulted {1} else {0}; + rbml_w.wr_tagged_u8(tag_defaulted_trait, byte); +} + +fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[Name]) { + rbml_w.start_tag(tag_associated_type_names); + for &name in names { + rbml_w.wr_tagged_str(tag_associated_type_name, &name.as_str()); + } + rbml_w.end_tag(); +} + +fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) { + let byte: u8 = match polarity { + hir::ImplPolarity::Positive => 0, + hir::ImplPolarity::Negative => 1, + }; + rbml_w.wr_tagged_u8(tag_polarity, byte); +} + +fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { + fn get_ordered_deps(cstore: &cstore::CStore) + -> Vec<(CrateNum, Rc)> { + // Pull the cnums and name,vers,hash out of cstore + let mut deps = Vec::new(); + cstore.iter_crate_data(|cnum, val| { + deps.push((cnum, val.clone())); + }); + + // Sort by cnum + deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0)); + + // Sanity-check the crate numbers + let mut expected_cnum = 1; + for &(n, _) in &deps { + assert_eq!(n, expected_cnum); + expected_cnum += 1; + } + + deps + } + + // We're just going to write a list of crate 'name-hash-version's, with + // the assumption that they are numbered 1 to n. + // FIXME (#2166): This is not nearly enough to support correct versioning + // but is enough to get transitive crate dependencies working. + rbml_w.start_tag(tag_crate_deps); + for (_cnum, dep) in get_ordered_deps(cstore) { + encode_crate_dep(rbml_w, &dep); + } + rbml_w.end_tag(); +} + +fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) { + rbml_w.start_tag(tag_lang_items); + + for (i, &opt_def_id) in ecx.tcx.lang_items.items() { + if let Some(def_id) = opt_def_id { + if def_id.is_local() { + rbml_w.start_tag(tag_lang_items_item); + rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32); + rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32()); + rbml_w.end_tag(); + } + } + } + + for i in &ecx.tcx.lang_items.missing { + rbml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32); + } + + rbml_w.end_tag(); // tag_lang_items +} + +fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) { + rbml_w.start_tag(tag_native_libraries); + + for &(ref lib, kind) in ecx.tcx.sess.cstore.used_libraries().iter() { + match kind { + cstore::NativeStatic => {} // these libraries are not propagated + cstore::NativeFramework | cstore::NativeUnknown => { + rbml_w.start_tag(tag_native_libraries_lib); + rbml_w.wr_tagged_u32(tag_native_libraries_kind, kind as u32); + rbml_w.wr_tagged_str(tag_native_libraries_name, lib); + rbml_w.end_tag(); + } + } + } + + rbml_w.end_tag(); +} + +fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) { + match ecx.tcx.sess.plugin_registrar_fn.get() { + Some(id) => { + let def_id = ecx.tcx.map.local_def_id(id); + rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32()); + } + None => {} + } +} + +fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { + rbml_w.start_tag(tag_codemap); + let codemap = ecx.tcx.sess.codemap(); + + for filemap in &codemap.files.borrow()[..] { + + if filemap.lines.borrow().is_empty() || filemap.is_imported() { + // No need to export empty filemaps, as they can't contain spans + // that need translation. + // Also no need to re-export imported filemaps, as any downstream + // crate will import them from their original source. + continue; + } + + rbml_w.start_tag(tag_codemap_filemap); + filemap.encode(rbml_w); + rbml_w.end_tag(); + } + + rbml_w.end_tag(); +} + +/// Serialize the text of the exported macros +fn encode_macro_defs(rbml_w: &mut Encoder, + krate: &hir::Crate) { + rbml_w.start_tag(tag_macro_defs); + for def in &krate.exported_macros { + rbml_w.start_tag(tag_macro_def); + + encode_name(rbml_w, def.name); + encode_attributes(rbml_w, &def.attrs); + + rbml_w.wr_tagged_str(tag_macro_def_body, + &::syntax::print::pprust::tts_to_string(&def.body)); + + rbml_w.end_tag(); + } + rbml_w.end_tag(); +} + +fn encode_struct_field_attrs(ecx: &EncodeContext, + rbml_w: &mut Encoder, + krate: &hir::Crate) { + struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> { + ecx: &'a EncodeContext<'b, 'tcx>, + rbml_w: &'a mut Encoder<'c>, + } + + impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> { + fn visit_struct_field(&mut self, field: &hir::StructField) { + self.rbml_w.start_tag(tag_struct_field); + let def_id = self.ecx.tcx.map.local_def_id(field.node.id); + encode_def_id(self.rbml_w, def_id); + encode_attributes(self.rbml_w, &field.node.attrs); + self.rbml_w.end_tag(); + } + } + + rbml_w.start_tag(tag_struct_fields); + krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w }); + rbml_w.end_tag(); +} + + + +struct ImplVisitor<'a, 'tcx:'a> { + tcx: &'a ty::ctxt<'tcx>, + impls: FnvHashMap> +} + +impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + if let hir::ItemImpl(..) = item.node { + let impl_id = self.tcx.map.local_def_id(item.id); + if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) { + self.impls.entry(trait_ref.def_id) + .or_insert(vec![]) + .push(impl_id); + } + } + } +} + +/// Encodes an index, mapping each trait to its (local) implementations. +fn encode_impls<'a>(ecx: &'a EncodeContext, + krate: &hir::Crate, + rbml_w: &'a mut Encoder) { + let mut visitor = ImplVisitor { + tcx: ecx.tcx, + impls: FnvHashMap() + }; + krate.visit_all_items(&mut visitor); + + rbml_w.start_tag(tag_impls); + for (trait_, trait_impls) in visitor.impls { + rbml_w.start_tag(tag_impls_trait); + encode_def_id(rbml_w, trait_); + for impl_ in trait_impls { + rbml_w.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_)); + } + rbml_w.end_tag(); + } + rbml_w.end_tag(); +} + +fn encode_misc_info(ecx: &EncodeContext, + krate: &hir::Crate, + rbml_w: &mut Encoder) { + rbml_w.start_tag(tag_misc_info); + rbml_w.start_tag(tag_misc_info_crate_items); + for item_id in &krate.module.item_ids { + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); + + let item = ecx.tcx.map.expect_item(item_id.id); + each_auxiliary_node_id(item, |auxiliary_node_id| { + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); + true + }); + } + + // Encode reexports for the root module. + encode_reexports(ecx, rbml_w, 0); + + rbml_w.end_tag(); + rbml_w.end_tag(); +} + +// Encodes all reachable symbols in this crate into the metadata. +// +// This pass is seeded off the reachability list calculated in the +// middle::reachable module but filters out items that either don't have a +// symbol associated with them (they weren't translated) or if they're an FFI +// definition (as that's not defined in this crate). +fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) { + rbml_w.start_tag(tag_reachable_ids); + for &id in ecx.reachable { + let def_id = ecx.tcx.map.local_def_id(id); + rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32()); + } + rbml_w.end_tag(); +} + +fn encode_crate_dep(rbml_w: &mut Encoder, + dep: &cstore::crate_metadata) { + rbml_w.start_tag(tag_crate_dep); + rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); + let hash = decoder::get_crate_hash(dep.data()); + rbml_w.wr_tagged_str(tag_crate_dep_hash, hash.as_str()); + rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked, + dep.explicitly_linked.get() as u8); + rbml_w.end_tag(); +} + +fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) { + rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str()); +} + +fn encode_rustc_version(rbml_w: &mut Encoder) { + rbml_w.wr_tagged_str(tag_rustc_version, &rustc_version()); +} + +fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) { + rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name); +} + +fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) { + rbml_w.wr_tagged_str(tag_crate_triple, triple); +} + +fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) { + let tag = tag_dylib_dependency_formats; + match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { + Some(arr) => { + let s = arr.iter().enumerate().filter_map(|(i, slot)| { + let kind = match *slot { + Linkage::NotLinked | + Linkage::IncludedFromDylib => return None, + Linkage::Dynamic => "d", + Linkage::Static => "s", + }; + Some(format!("{}:{}", i + 1, kind)) + }).collect::>(); + rbml_w.wr_tagged_str(tag, &s.join(",")); + } + None => { + rbml_w.wr_tagged_str(tag, ""); + } + } +} + +// NB: Increment this as you change the metadata encoding version. +#[allow(non_upper_case_globals)] +pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ]; + +pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec { + let mut wr = Cursor::new(Vec::new()); + encode_metadata_inner(&mut wr, parms, krate); + + // RBML compacts the encoded bytes whenever appropriate, + // so there are some garbages left after the end of the data. + let metalen = wr.seek(SeekFrom::Current(0)).unwrap() as usize; + let mut v = wr.into_inner(); + v.truncate(metalen); + assert_eq!(v.len(), metalen); + + // And here we run into yet another obscure archive bug: in which metadata + // loaded from archives may have trailing garbage bytes. Awhile back one of + // our tests was failing sporadically on the OSX 64-bit builders (both nopt + // and opt) by having rbml generate an out-of-bounds panic when looking at + // metadata. + // + // Upon investigation it turned out that the metadata file inside of an rlib + // (and ar archive) was being corrupted. Some compilations would generate a + // metadata file which would end in a few extra bytes, while other + // compilations would not have these extra bytes appended to the end. These + // extra bytes were interpreted by rbml as an extra tag, so they ended up + // being interpreted causing the out-of-bounds. + // + // The root cause of why these extra bytes were appearing was never + // discovered, and in the meantime the solution we're employing is to insert + // the length of the metadata to the start of the metadata. Later on this + // will allow us to slice the metadata to the precise length that we just + // generated regardless of trailing bytes that end up in it. + let len = v.len() as u32; + v.insert(0, (len >> 0) as u8); + v.insert(0, (len >> 8) as u8); + v.insert(0, (len >> 16) as u8); + v.insert(0, (len >> 24) as u8); + return v; +} + +fn encode_metadata_inner(wr: &mut Cursor>, + parms: EncodeParams, + krate: &hir::Crate) { + struct Stats { + attr_bytes: u64, + dep_bytes: u64, + lang_item_bytes: u64, + native_lib_bytes: u64, + plugin_registrar_fn_bytes: u64, + codemap_bytes: u64, + macro_defs_bytes: u64, + impl_bytes: u64, + misc_bytes: u64, + item_bytes: u64, + index_bytes: u64, + xref_bytes: u64, + zero_bytes: u64, + total_bytes: u64, + } + let mut stats = Stats { + attr_bytes: 0, + dep_bytes: 0, + lang_item_bytes: 0, + native_lib_bytes: 0, + plugin_registrar_fn_bytes: 0, + codemap_bytes: 0, + macro_defs_bytes: 0, + impl_bytes: 0, + misc_bytes: 0, + item_bytes: 0, + index_bytes: 0, + xref_bytes: 0, + zero_bytes: 0, + total_bytes: 0, + }; + let EncodeParams { + item_symbols, + diag, + tcx, + reexports, + cstore, + encode_inlined_item, + link_meta, + reachable, + .. + } = parms; + let ecx = EncodeContext { + diag: diag, + tcx: tcx, + reexports: reexports, + item_symbols: item_symbols, + link_meta: link_meta, + cstore: cstore, + encode_inlined_item: RefCell::new(encode_inlined_item), + type_abbrevs: RefCell::new(FnvHashMap()), + reachable: reachable, + }; + + let mut rbml_w = Encoder::new(wr); + + encode_rustc_version(&mut rbml_w); + encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name); + encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple); + encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash); + encode_dylib_dependency_formats(&mut rbml_w, &ecx); + + let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_attributes(&mut rbml_w, &krate.attrs); + stats.attr_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_crate_deps(&mut rbml_w, ecx.cstore); + stats.dep_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + // Encode the language items. + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_lang_items(&ecx, &mut rbml_w); + stats.lang_item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + // Encode the native libraries used + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_native_libraries(&ecx, &mut rbml_w); + stats.native_lib_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + // Encode the plugin registrar function + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_plugin_registrar_fn(&ecx, &mut rbml_w); + stats.plugin_registrar_fn_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + // Encode codemap + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_codemap(&ecx, &mut rbml_w); + stats.codemap_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + // Encode macro definitions + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_macro_defs(&mut rbml_w, krate); + stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + // Encode the def IDs of impls, for coherence checking. + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_impls(&ecx, krate, &mut rbml_w); + stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + // Encode miscellaneous info. + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_misc_info(&ecx, krate, &mut rbml_w); + encode_reachable(&ecx, &mut rbml_w); + stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + // Encode and index the items. + rbml_w.start_tag(tag_items); + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + let index = encode_info_for_items(&ecx, &mut rbml_w); + stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + rbml_w.end_tag(); + + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_item_index(&mut rbml_w, index.items); + stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_xrefs(&ecx, &mut rbml_w, index.xrefs); + stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + encode_struct_field_attrs(&ecx, &mut rbml_w, krate); + + stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + + if tcx.sess.meta_stats() { + for e in rbml_w.writer.get_ref() { + if *e == 0 { + stats.zero_bytes += 1; + } + } + + println!("metadata stats:"); + println!(" attribute bytes: {}", stats.attr_bytes); + println!(" dep bytes: {}", stats.dep_bytes); + println!(" lang item bytes: {}", stats.lang_item_bytes); + println!(" native bytes: {}", stats.native_lib_bytes); + println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes); + println!(" codemap bytes: {}", stats.codemap_bytes); + println!(" macro def bytes: {}", stats.macro_defs_bytes); + println!(" impl bytes: {}", stats.impl_bytes); + println!(" misc bytes: {}", stats.misc_bytes); + println!(" item bytes: {}", stats.item_bytes); + println!(" index bytes: {}", stats.index_bytes); + println!(" xref bytes: {}", stats.xref_bytes); + println!(" zero bytes: {}", stats.zero_bytes); + println!(" total bytes: {}", stats.total_bytes); + } +} + +// Get the encoded string for a type +pub fn encoded_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> Vec { + let mut wr = Cursor::new(Vec::new()); + tyencode::enc_ty(&mut Encoder::new(&mut wr), &tyencode::ctxt { + diag: tcx.sess.diagnostic(), + ds: def_to_string, + tcx: tcx, + abbrevs: &RefCell::new(FnvHashMap()) + }, t); + wr.into_inner() +} diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs new file mode 100644 index 00000000000..60bbdaddd75 --- /dev/null +++ b/src/librustc_metadata/index.rs @@ -0,0 +1,145 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::def_id::{DefId, DefIndex}; +use rbml; +use std::io::{Cursor, Write}; +use std::slice; +use std::u32; + +/// As part of the metadata, we generate an index that stores, for +/// each DefIndex, the position of the corresponding RBML document (if +/// any). This is just a big `[u32]` slice, where an entry of +/// `u32::MAX` indicates that there is no RBML document. This little +/// struct just stores the offsets within the metadata of the start +/// and end of this slice. These are actually part of an RBML +/// document, but for looking things up in the metadata, we just +/// discard the RBML positioning and jump directly to the data. +pub struct Index { + data_start: usize, + data_end: usize, +} + +impl Index { + /// Given the RBML doc representing the index, save the offests + /// for later. + pub fn from_rbml(index: rbml::Doc) -> Index { + Index { data_start: index.start, data_end: index.end } + } + + /// Given the metadata, extract out the offset of a particular + /// DefIndex (if any). + #[inline(never)] + pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option { + let words = bytes_to_words(&bytes[self.data_start..self.data_end]); + let index = def_index.as_usize(); + + debug!("lookup_item: index={:?} words.len={:?}", + index, words.len()); + + let position = u32::from_be(words[index]); + if position == u32::MAX { + debug!("lookup_item: position=u32::MAX"); + None + } else { + debug!("lookup_item: position={:?}", position); + Some(position) + } + } +} + +/// While we are generating the metadata, we also track the position +/// of each DefIndex. It is not required that all definitions appear +/// in the metadata, nor that they are serialized in order, and +/// therefore we first allocate the vector here and fill it with +/// `u32::MAX`. Whenever an index is visited, we fill in the +/// appropriate spot by calling `record_position`. We should never +/// visit the same index twice. +pub struct IndexData { + positions: Vec, +} + +impl IndexData { + pub fn new(max_index: usize) -> IndexData { + IndexData { + positions: vec![u32::MAX; max_index] + } + } + + pub fn record(&mut self, def_id: DefId, position: u64) { + assert!(def_id.is_local()); + self.record_index(def_id.index, position) + } + + pub fn record_index(&mut self, item: DefIndex, position: u64) { + let item = item.as_usize(); + + assert!(position < (u32::MAX as u64)); + let position = position as u32; + + assert!(self.positions[item] == u32::MAX, + "recorded position for item {:?} twice, first at {:?} and now at {:?}", + item, self.positions[item], position); + + self.positions[item] = position; + } + + pub fn write_index(&self, buf: &mut Cursor>) { + for &position in &self.positions { + write_be_u32(buf, position); + } + } +} + +/// A dense index with integer keys. Different API from IndexData (should +/// these be merged?) +pub struct DenseIndex { + start: usize, + end: usize +} + +impl DenseIndex { + pub fn lookup(&self, buf: &[u8], ix: u32) -> Option { + let data = bytes_to_words(&buf[self.start..self.end]); + data.get(ix as usize).map(|d| u32::from_be(*d)) + } + pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self { + assert!((end-start)%4 == 0 && start <= end && end <= buf.len()); + DenseIndex { + start: start, + end: end + } + } +} + +pub fn write_dense_index(entries: Vec, buf: &mut Cursor>) { + let elen = entries.len(); + assert!(elen < u32::MAX as usize); + + for entry in entries { + write_be_u32(buf, entry); + } + + info!("write_dense_index: {} entries", elen); +} + +fn write_be_u32(w: &mut W, u: u32) { + let _ = w.write_all(&[ + (u >> 24) as u8, + (u >> 16) as u8, + (u >> 8) as u8, + (u >> 0) as u8, + ]); +} + +fn bytes_to_words(b: &[u8]) -> &[u32] { + assert!(b.len() % 4 == 0); + unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) } +} diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs new file mode 100644 index 00000000000..6affbd2b593 --- /dev/null +++ b/src/librustc_metadata/lib.rs @@ -0,0 +1,61 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(stage0, feature(custom_attribute))] +#![crate_name = "rustc_metadata"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![cfg_attr(stage0, staged_api)] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] + +#![feature(box_patterns)] +#![feature(duration_span)] +#![feature(enumset)] +#![feature(quote)] +#![feature(staged_api)] +#![feature(vec_push_all)] +#![feature(rustc_diagnostic_macros)] +#![feature(rustc_private)] + +#[macro_use] extern crate log; +#[macro_use] extern crate syntax; +#[macro_use] #[no_link] extern crate rustc_bitflags; + +extern crate flate; +extern crate rbml; +extern crate serialize; + +extern crate rustc; +extern crate rustc_back; +extern crate rustc_front; +extern crate rustc_llvm; + +pub use rustc::middle; + +#[macro_use] +mod macros; + +pub mod diagnostics; + +pub mod astencode; +pub mod common; +pub mod tyencode; +pub mod tydecode; +pub mod encoder; +pub mod decoder; +pub mod creader; +pub mod csearch; +pub mod cstore; +pub mod index; +pub mod loader; +pub mod macro_import; diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs new file mode 100644 index 00000000000..72938a7660a --- /dev/null +++ b/src/librustc_metadata/loader.rs @@ -0,0 +1,854 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Finds crate binaries and loads their metadata +//! +//! Might I be the first to welcome you to a world of platform differences, +//! version requirements, dependency graphs, conflicting desires, and fun! This +//! is the major guts (along with metadata::creader) of the compiler for loading +//! crates and resolving dependencies. Let's take a tour! +//! +//! # The problem +//! +//! Each invocation of the compiler is immediately concerned with one primary +//! problem, to connect a set of crates to resolved crates on the filesystem. +//! Concretely speaking, the compiler follows roughly these steps to get here: +//! +//! 1. Discover a set of `extern crate` statements. +//! 2. Transform these directives into crate names. If the directive does not +//! have an explicit name, then the identifier is the name. +//! 3. For each of these crate names, find a corresponding crate on the +//! filesystem. +//! +//! Sounds easy, right? Let's walk into some of the nuances. +//! +//! ## Transitive Dependencies +//! +//! Let's say we've got three crates: A, B, and C. A depends on B, and B depends +//! on C. When we're compiling A, we primarily need to find and locate B, but we +//! also end up needing to find and locate C as well. +//! +//! The reason for this is that any of B's types could be composed of C's types, +//! any function in B could return a type from C, etc. To be able to guarantee +//! that we can always typecheck/translate any function, we have to have +//! complete knowledge of the whole ecosystem, not just our immediate +//! dependencies. +//! +//! So now as part of the "find a corresponding crate on the filesystem" step +//! above, this involves also finding all crates for *all upstream +//! dependencies*. This includes all dependencies transitively. +//! +//! ## Rlibs and Dylibs +//! +//! The compiler has two forms of intermediate dependencies. These are dubbed +//! rlibs and dylibs for the static and dynamic variants, respectively. An rlib +//! is a rustc-defined file format (currently just an ar archive) while a dylib +//! is a platform-defined dynamic library. Each library has a metadata somewhere +//! inside of it. +//! +//! When translating a crate name to a crate on the filesystem, we all of a +//! sudden need to take into account both rlibs and dylibs! Linkage later on may +//! use either one of these files, as each has their pros/cons. The job of crate +//! loading is to discover what's possible by finding all candidates. +//! +//! Most parts of this loading systems keep the dylib/rlib as just separate +//! variables. +//! +//! ## Where to look? +//! +//! We can't exactly scan your whole hard drive when looking for dependencies, +//! so we need to places to look. Currently the compiler will implicitly add the +//! target lib search path ($prefix/lib/rustlib/$target/lib) to any compilation, +//! and otherwise all -L flags are added to the search paths. +//! +//! ## What criterion to select on? +//! +//! This a pretty tricky area of loading crates. Given a file, how do we know +//! whether it's the right crate? Currently, the rules look along these lines: +//! +//! 1. Does the filename match an rlib/dylib pattern? That is to say, does the +//! filename have the right prefix/suffix? +//! 2. Does the filename have the right prefix for the crate name being queried? +//! This is filtering for files like `libfoo*.rlib` and such. +//! 3. Is the file an actual rust library? This is done by loading the metadata +//! from the library and making sure it's actually there. +//! 4. Does the name in the metadata agree with the name of the library? +//! 5. Does the target in the metadata agree with the current target? +//! 6. Does the SVH match? (more on this later) +//! +//! If the file answers `yes` to all these questions, then the file is +//! considered as being *candidate* for being accepted. It is illegal to have +//! more than two candidates as the compiler has no method by which to resolve +//! this conflict. Additionally, rlib/dylib candidates are considered +//! separately. +//! +//! After all this has happened, we have 1 or two files as candidates. These +//! represent the rlib/dylib file found for a library, and they're returned as +//! being found. +//! +//! ### What about versions? +//! +//! A lot of effort has been put forth to remove versioning from the compiler. +//! There have been forays in the past to have versioning baked in, but it was +//! largely always deemed insufficient to the point that it was recognized that +//! it's probably something the compiler shouldn't do anyway due to its +//! complicated nature and the state of the half-baked solutions. +//! +//! With a departure from versioning, the primary criterion for loading crates +//! is just the name of a crate. If we stopped here, it would imply that you +//! could never link two crates of the same name from different sources +//! together, which is clearly a bad state to be in. +//! +//! To resolve this problem, we come to the next section! +//! +//! # Expert Mode +//! +//! A number of flags have been added to the compiler to solve the "version +//! problem" in the previous section, as well as generally enabling more +//! powerful usage of the crate loading system of the compiler. The goal of +//! these flags and options are to enable third-party tools to drive the +//! compiler with prior knowledge about how the world should look. +//! +//! ## The `--extern` flag +//! +//! The compiler accepts a flag of this form a number of times: +//! +//! ```text +//! --extern crate-name=path/to/the/crate.rlib +//! ``` +//! +//! This flag is basically the following letter to the compiler: +//! +//! > Dear rustc, +//! > +//! > When you are attempting to load the immediate dependency `crate-name`, I +//! > would like you to assume that the library is located at +//! > `path/to/the/crate.rlib`, and look nowhere else. Also, please do not +//! > assume that the path I specified has the name `crate-name`. +//! +//! This flag basically overrides most matching logic except for validating that +//! the file is indeed a rust library. The same `crate-name` can be specified +//! twice to specify the rlib/dylib pair. +//! +//! ## Enabling "multiple versions" +//! +//! This basically boils down to the ability to specify arbitrary packages to +//! the compiler. For example, if crate A wanted to use Bv1 and Bv2, then it +//! would look something like: +//! +//! ```ignore +//! extern crate b1; +//! extern crate b2; +//! +//! fn main() {} +//! ``` +//! +//! and the compiler would be invoked as: +//! +//! ```text +//! rustc a.rs --extern b1=path/to/libb1.rlib --extern b2=path/to/libb2.rlib +//! ``` +//! +//! In this scenario there are two crates named `b` and the compiler must be +//! manually driven to be informed where each crate is. +//! +//! ## Frobbing symbols +//! +//! One of the immediate problems with linking the same library together twice +//! in the same problem is dealing with duplicate symbols. The primary way to +//! deal with this in rustc is to add hashes to the end of each symbol. +//! +//! In order to force hashes to change between versions of a library, if +//! desired, the compiler exposes an option `-C metadata=foo`, which is used to +//! initially seed each symbol hash. The string `foo` is prepended to each +//! string-to-hash to ensure that symbols change over time. +//! +//! ## Loading transitive dependencies +//! +//! Dealing with same-named-but-distinct crates is not just a local problem, but +//! one that also needs to be dealt with for transitive dependencies. Note that +//! in the letter above `--extern` flags only apply to the *local* set of +//! dependencies, not the upstream transitive dependencies. Consider this +//! dependency graph: +//! +//! ```text +//! A.1 A.2 +//! | | +//! | | +//! B C +//! \ / +//! \ / +//! D +//! ``` +//! +//! In this scenario, when we compile `D`, we need to be able to distinctly +//! resolve `A.1` and `A.2`, but an `--extern` flag cannot apply to these +//! transitive dependencies. +//! +//! Note that the key idea here is that `B` and `C` are both *already compiled*. +//! That is, they have already resolved their dependencies. Due to unrelated +//! technical reasons, when a library is compiled, it is only compatible with +//! the *exact same* version of the upstream libraries it was compiled against. +//! We use the "Strict Version Hash" to identify the exact copy of an upstream +//! library. +//! +//! With this knowledge, we know that `B` and `C` will depend on `A` with +//! different SVH values, so we crawl the normal `-L` paths looking for +//! `liba*.rlib` and filter based on the contained SVH. +//! +//! In the end, this ends up not needing `--extern` to specify upstream +//! transitive dependencies. +//! +//! # Wrapping up +//! +//! That's the general overview of loading crates in the compiler, but it's by +//! no means all of the necessary details. Take a look at the rest of +//! metadata::loader or metadata::creader for all the juicy details! + +use cstore::{MetadataBlob, MetadataVec, MetadataArchive}; +use decoder; +use encoder; + +use rustc::back::svh::Svh; +use rustc::session::Session; +use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; +use rustc::session::search_paths::PathKind; +use rustc::util::common; + +use rustc_llvm as llvm; +use rustc_llvm::{False, ObjectFile, mk_section_iter}; +use rustc_llvm::archive_ro::ArchiveRO; +use syntax::codemap::Span; +use syntax::diagnostic::SpanHandler; +use rustc_back::target::Target; + +use std::cmp; +use std::collections::HashMap; +use std::fs; +use std::io::prelude::*; +use std::io; +use std::path::{Path, PathBuf}; +use std::ptr; +use std::slice; +use std::time::Duration; + +use flate; + +pub struct CrateMismatch { + path: PathBuf, + got: String, +} + +pub struct Context<'a> { + pub sess: &'a Session, + pub span: Span, + pub ident: &'a str, + pub crate_name: &'a str, + pub hash: Option<&'a Svh>, + // points to either self.sess.target.target or self.sess.host, must match triple + pub target: &'a Target, + pub triple: &'a str, + pub filesearch: FileSearch<'a>, + pub root: &'a Option, + pub rejected_via_hash: Vec, + pub rejected_via_triple: Vec, + pub rejected_via_kind: Vec, + pub should_match_name: bool, +} + +pub struct Library { + pub dylib: Option<(PathBuf, PathKind)>, + pub rlib: Option<(PathBuf, PathKind)>, + pub metadata: MetadataBlob, +} + +pub struct ArchiveMetadata { + _archive: ArchiveRO, + // points into self._archive + data: *const [u8], +} + +pub struct CratePaths { + pub ident: String, + pub dylib: Option, + pub rlib: Option +} + +pub const METADATA_FILENAME: &'static str = "rust.metadata.bin"; + +impl CratePaths { + fn paths(&self) -> Vec { + match (&self.dylib, &self.rlib) { + (&None, &None) => vec!(), + (&Some(ref p), &None) | + (&None, &Some(ref p)) => vec!(p.clone()), + (&Some(ref p1), &Some(ref p2)) => vec!(p1.clone(), p2.clone()), + } + } +} + +impl<'a> Context<'a> { + pub fn maybe_load_library_crate(&mut self) -> Option { + self.find_library_crate() + } + + pub fn load_library_crate(&mut self) -> Library { + match self.find_library_crate() { + Some(t) => t, + None => { + self.report_load_errs(); + unreachable!() + } + } + } + + pub fn report_load_errs(&mut self) { + let add = match self.root { + &None => String::new(), + &Some(ref r) => format!(" which `{}` depends on", + r.ident) + }; + if !self.rejected_via_hash.is_empty() { + span_err!(self.sess, self.span, E0460, + "found possibly newer version of crate `{}`{}", + self.ident, add); + } else if !self.rejected_via_triple.is_empty() { + span_err!(self.sess, self.span, E0461, + "couldn't find crate `{}` with expected target triple {}{}", + self.ident, self.triple, add); + } else if !self.rejected_via_kind.is_empty() { + span_err!(self.sess, self.span, E0462, + "found staticlib `{}` instead of rlib or dylib{}", + self.ident, add); + } else { + span_err!(self.sess, self.span, E0463, + "can't find crate for `{}`{}", + self.ident, add); + } + + if !self.rejected_via_triple.is_empty() { + let mismatches = self.rejected_via_triple.iter(); + for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() { + self.sess.fileline_note(self.span, + &format!("crate `{}`, path #{}, triple {}: {}", + self.ident, i+1, got, path.display())); + } + } + if !self.rejected_via_hash.is_empty() { + self.sess.span_note(self.span, "perhaps this crate needs \ + to be recompiled?"); + let mismatches = self.rejected_via_hash.iter(); + for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() { + self.sess.fileline_note(self.span, + &format!("crate `{}` path #{}: {}", + self.ident, i+1, path.display())); + } + match self.root { + &None => {} + &Some(ref r) => { + for (i, path) in r.paths().iter().enumerate() { + self.sess.fileline_note(self.span, + &format!("crate `{}` path #{}: {}", + r.ident, i+1, path.display())); + } + } + } + } + if !self.rejected_via_kind.is_empty() { + self.sess.fileline_help(self.span, "please recompile this crate using \ + --crate-type lib"); + let mismatches = self.rejected_via_kind.iter(); + for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { + self.sess.fileline_note(self.span, + &format!("crate `{}` path #{}: {}", + self.ident, i+1, path.display())); + } + } + self.sess.abort_if_errors(); + } + + fn find_library_crate(&mut self) -> Option { + // If an SVH is specified, then this is a transitive dependency that + // must be loaded via -L plus some filtering. + if self.hash.is_none() { + self.should_match_name = false; + if let Some(s) = self.sess.opts.externs.get(self.crate_name) { + return self.find_commandline_library(s); + } + self.should_match_name = true; + } + + let dypair = self.dylibname(); + + // want: crate_name.dir_part() + prefix + crate_name.file_part + "-" + let dylib_prefix = format!("{}{}", dypair.0, self.crate_name); + let rlib_prefix = format!("lib{}", self.crate_name); + let staticlib_prefix = format!("lib{}", self.crate_name); + + let mut candidates = HashMap::new(); + let mut staticlibs = vec!(); + + // First, find all possible candidate rlibs and dylibs purely based on + // the name of the files themselves. We're trying to match against an + // exact crate name and a possibly an exact hash. + // + // During this step, we can filter all found libraries based on the + // name and id found in the crate id (we ignore the path portion for + // filename matching), as well as the exact hash (if specified). If we + // end up having many candidates, we must look at the metadata to + // perform exact matches against hashes/crate ids. Note that opening up + // the metadata is where we do an exact match against the full contents + // of the crate id (path/name/id). + // + // The goal of this step is to look at as little metadata as possible. + self.filesearch.search(|path, kind| { + let file = match path.file_name().and_then(|s| s.to_str()) { + None => return FileDoesntMatch, + Some(file) => file, + }; + let (hash, rlib) = if file.starts_with(&rlib_prefix[..]) && + file.ends_with(".rlib") { + (&file[(rlib_prefix.len()) .. (file.len() - ".rlib".len())], + true) + } else if file.starts_with(&dylib_prefix) && + file.ends_with(&dypair.1) { + (&file[(dylib_prefix.len()) .. (file.len() - dypair.1.len())], + false) + } else { + if file.starts_with(&staticlib_prefix[..]) && + file.ends_with(".a") { + staticlibs.push(CrateMismatch { + path: path.to_path_buf(), + got: "static".to_string() + }); + } + return FileDoesntMatch + }; + info!("lib candidate: {}", path.display()); + + let hash_str = hash.to_string(); + let slot = candidates.entry(hash_str) + .or_insert_with(|| (HashMap::new(), HashMap::new())); + let (ref mut rlibs, ref mut dylibs) = *slot; + fs::canonicalize(path).map(|p| { + if rlib { + rlibs.insert(p, kind); + } else { + dylibs.insert(p, kind); + } + FileMatches + }).unwrap_or(FileDoesntMatch) + }); + self.rejected_via_kind.extend(staticlibs); + + // We have now collected all known libraries into a set of candidates + // keyed of the filename hash listed. For each filename, we also have a + // list of rlibs/dylibs that apply. Here, we map each of these lists + // (per hash), to a Library candidate for returning. + // + // A Library candidate is created if the metadata for the set of + // libraries corresponds to the crate id and hash criteria that this + // search is being performed for. + let mut libraries = Vec::new(); + for (_hash, (rlibs, dylibs)) in candidates { + let mut metadata = None; + let rlib = self.extract_one(rlibs, "rlib", &mut metadata); + let dylib = self.extract_one(dylibs, "dylib", &mut metadata); + match metadata { + Some(metadata) => { + libraries.push(Library { + dylib: dylib, + rlib: rlib, + metadata: metadata, + }) + } + None => {} + } + } + + // Having now translated all relevant found hashes into libraries, see + // what we've got and figure out if we found multiple candidates for + // libraries or not. + match libraries.len() { + 0 => None, + 1 => Some(libraries.into_iter().next().unwrap()), + _ => { + span_err!(self.sess, self.span, E0464, + "multiple matching crates for `{}`", + self.crate_name); + self.sess.note("candidates:"); + for lib in &libraries { + match lib.dylib { + Some((ref p, _)) => { + self.sess.note(&format!("path: {}", + p.display())); + } + None => {} + } + match lib.rlib { + Some((ref p, _)) => { + self.sess.note(&format!("path: {}", + p.display())); + } + None => {} + } + let data = lib.metadata.as_slice(); + let name = decoder::get_crate_name(data); + note_crate_name(self.sess.diagnostic(), &name); + } + None + } + } + } + + // Attempts to extract *one* library from the set `m`. If the set has no + // elements, `None` is returned. If the set has more than one element, then + // the errors and notes are emitted about the set of libraries. + // + // With only one library in the set, this function will extract it, and then + // read the metadata from it if `*slot` is `None`. If the metadata couldn't + // be read, it is assumed that the file isn't a valid rust library (no + // errors are emitted). + fn extract_one(&mut self, m: HashMap, flavor: &str, + slot: &mut Option) -> Option<(PathBuf, PathKind)> { + let mut ret = None::<(PathBuf, PathKind)>; + let mut error = 0; + + if slot.is_some() { + // FIXME(#10786): for an optimization, we only read one of the + // library's metadata sections. In theory we should + // read both, but reading dylib metadata is quite + // slow. + if m.is_empty() { + return None + } else if m.len() == 1 { + return Some(m.into_iter().next().unwrap()) + } + } + + for (lib, kind) in m { + info!("{} reading metadata from: {}", flavor, lib.display()); + let metadata = match get_metadata_section(self.target, &lib) { + Ok(blob) => { + if self.crate_matches(blob.as_slice(), &lib) { + blob + } else { + info!("metadata mismatch"); + continue + } + } + Err(err) => { + info!("no metadata found: {}", err); + continue + } + }; + // If we've already found a candidate and we're not matching hashes, + // emit an error about duplicate candidates found. If we're matching + // based on a hash, however, then if we've gotten this far both + // candidates have the same hash, so they're not actually + // duplicates that we should warn about. + if ret.is_some() && self.hash.is_none() { + span_err!(self.sess, self.span, E0465, + "multiple {} candidates for `{}` found", + flavor, self.crate_name); + self.sess.span_note(self.span, + &format!(r"candidate #1: {}", + ret.as_ref().unwrap().0 + .display())); + error = 1; + ret = None; + } + if error > 0 { + error += 1; + self.sess.span_note(self.span, + &format!(r"candidate #{}: {}", error, + lib.display())); + continue + } + *slot = Some(metadata); + ret = Some((lib, kind)); + } + return if error > 0 {None} else {ret} + } + + fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> bool { + if self.should_match_name { + match decoder::maybe_get_crate_name(crate_data) { + Some(ref name) if self.crate_name == *name => {} + _ => { info!("Rejecting via crate name"); return false } + } + } + let hash = match decoder::maybe_get_crate_hash(crate_data) { + Some(hash) => hash, None => { + info!("Rejecting via lack of crate hash"); + return false; + } + }; + + let triple = match decoder::get_crate_triple(crate_data) { + None => { debug!("triple not present"); return false } + Some(t) => t, + }; + if triple != self.triple { + info!("Rejecting via crate triple: expected {} got {}", self.triple, triple); + self.rejected_via_triple.push(CrateMismatch { + path: libpath.to_path_buf(), + got: triple.to_string() + }); + return false; + } + + match self.hash { + None => true, + Some(myhash) => { + if *myhash != hash { + info!("Rejecting via hash: expected {} got {}", *myhash, hash); + self.rejected_via_hash.push(CrateMismatch { + path: libpath.to_path_buf(), + got: myhash.as_str().to_string() + }); + false + } else { + true + } + } + } + } + + + // Returns the corresponding (prefix, suffix) that files need to have for + // dynamic libraries + fn dylibname(&self) -> (String, String) { + let t = &self.target; + (t.options.dll_prefix.clone(), t.options.dll_suffix.clone()) + } + + fn find_commandline_library(&mut self, locs: &[String]) -> Option { + // First, filter out all libraries that look suspicious. We only accept + // files which actually exist that have the correct naming scheme for + // rlibs/dylibs. + let sess = self.sess; + let dylibname = self.dylibname(); + let mut rlibs = HashMap::new(); + let mut dylibs = HashMap::new(); + { + let locs = locs.iter().map(|l| PathBuf::from(l)).filter(|loc| { + if !loc.exists() { + sess.err(&format!("extern location for {} does not exist: {}", + self.crate_name, loc.display())); + return false; + } + let file = match loc.file_name().and_then(|s| s.to_str()) { + Some(file) => file, + None => { + sess.err(&format!("extern location for {} is not a file: {}", + self.crate_name, loc.display())); + return false; + } + }; + if file.starts_with("lib") && file.ends_with(".rlib") { + return true + } else { + let (ref prefix, ref suffix) = dylibname; + if file.starts_with(&prefix[..]) && + file.ends_with(&suffix[..]) { + return true + } + } + sess.err(&format!("extern location for {} is of an unknown type: {}", + self.crate_name, loc.display())); + false + }); + + // Now that we have an iterator of good candidates, make sure + // there's at most one rlib and at most one dylib. + for loc in locs { + if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") { + rlibs.insert(fs::canonicalize(&loc).unwrap(), + PathKind::ExternFlag); + } else { + dylibs.insert(fs::canonicalize(&loc).unwrap(), + PathKind::ExternFlag); + } + } + }; + + // Extract the rlib/dylib pair. + let mut metadata = None; + let rlib = self.extract_one(rlibs, "rlib", &mut metadata); + let dylib = self.extract_one(dylibs, "dylib", &mut metadata); + + if rlib.is_none() && dylib.is_none() { return None } + match metadata { + Some(metadata) => Some(Library { + dylib: dylib, + rlib: rlib, + metadata: metadata, + }), + None => None, + } + } +} + +pub fn note_crate_name(diag: &SpanHandler, name: &str) { + diag.handler().note(&format!("crate name: {}", name)); +} + +impl ArchiveMetadata { + fn new(ar: ArchiveRO) -> Option { + let data = { + let section = ar.iter().find(|sect| { + sect.name() == Some(METADATA_FILENAME) + }); + match section { + Some(s) => s.data() as *const [u8], + None => { + debug!("didn't find '{}' in the archive", METADATA_FILENAME); + return None; + } + } + }; + + Some(ArchiveMetadata { + _archive: ar, + data: data, + }) + } + + pub fn as_slice<'a>(&'a self) -> &'a [u8] { unsafe { &*self.data } } +} + +// Just a small wrapper to time how long reading metadata takes. +fn get_metadata_section(target: &Target, filename: &Path) + -> Result { + let mut ret = None; + let dur = Duration::span(|| { + ret = Some(get_metadata_section_imp(target, filename)); + }); + info!("reading {:?} => {:?}", filename.file_name().unwrap(), dur); + ret.unwrap() +} + +fn get_metadata_section_imp(target: &Target, filename: &Path) + -> Result { + if !filename.exists() { + return Err(format!("no such file: '{}'", filename.display())); + } + if filename.file_name().unwrap().to_str().unwrap().ends_with(".rlib") { + // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap + // internally to read the file. We also avoid even using a memcpy by + // just keeping the archive along while the metadata is in use. + let archive = match ArchiveRO::open(filename) { + Some(ar) => ar, + None => { + debug!("llvm didn't like `{}`", filename.display()); + return Err(format!("failed to read rlib metadata: '{}'", + filename.display())); + } + }; + return match ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)) { + None => Err(format!("failed to read rlib metadata: '{}'", + filename.display())), + Some(blob) => Ok(blob) + }; + } + unsafe { + let buf = common::path2cstr(filename); + let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); + if mb as isize == 0 { + return Err(format!("error reading library: '{}'", + filename.display())) + } + let of = match ObjectFile::new(mb) { + Some(of) => of, + _ => { + return Err((format!("provided path not an object file: '{}'", + filename.display()))) + } + }; + let si = mk_section_iter(of.llof); + while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { + let mut name_buf = ptr::null(); + let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); + let name = slice::from_raw_parts(name_buf as *const u8, + name_len as usize).to_vec(); + let name = String::from_utf8(name).unwrap(); + debug!("get_metadata_section: name {}", name); + if read_meta_section_name(target) == name { + let cbuf = llvm::LLVMGetSectionContents(si.llsi); + let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; + let cvbuf: *const u8 = cbuf as *const u8; + let vlen = encoder::metadata_encoding_version.len(); + debug!("checking {} bytes of metadata-version stamp", + vlen); + let minsz = cmp::min(vlen, csz); + let buf0 = slice::from_raw_parts(cvbuf, minsz); + let version_ok = buf0 == encoder::metadata_encoding_version; + if !version_ok { + return Err((format!("incompatible metadata version found: '{}'", + filename.display()))); + } + + let cvbuf1 = cvbuf.offset(vlen as isize); + debug!("inflating {} bytes of compressed metadata", + csz - vlen); + let bytes = slice::from_raw_parts(cvbuf1, csz - vlen); + match flate::inflate_bytes(bytes) { + Ok(inflated) => return Ok(MetadataVec(inflated)), + Err(_) => {} + } + } + llvm::LLVMMoveToNextSection(si.llsi); + } + Err(format!("metadata not found: '{}'", filename.display())) + } +} + +pub fn meta_section_name(target: &Target) -> &'static str { + if target.options.is_like_osx { + "__DATA,__note.rustc" + } else if target.options.is_like_msvc { + // When using link.exe it was seen that the section name `.note.rustc` + // was getting shortened to `.note.ru`, and according to the PE and COFF + // specification: + // + // > Executable images do not use a string table and do not support + // > section names longer than 8 characters + // + // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx + // + // As a result, we choose a slightly shorter name! As to why + // `.note.rustc` works on MinGW, that's another good question... + ".rustc" + } else { + ".note.rustc" + } +} + +pub fn read_meta_section_name(target: &Target) -> &'static str { + if target.options.is_like_osx { + "__note.rustc" + } else if target.options.is_like_msvc { + ".rustc" + } else { + ".note.rustc" + } +} + +// A diagnostic function for dumping crate metadata to an output stream +pub fn list_file_metadata(target: &Target, path: &Path, + out: &mut io::Write) -> io::Result<()> { + match get_metadata_section(target, path) { + Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out), + Err(msg) => { + write!(out, "{}\n", msg) + } + } +} diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs new file mode 100644 index 00000000000..d67fc3a0eab --- /dev/null +++ b/src/librustc_metadata/macro_import.rs @@ -0,0 +1,190 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Used by `rustc` when loading a crate with exported macros. + +use creader::CrateReader; +use cstore::CStore; + +use rustc::session::Session; + +use std::collections::{HashSet, HashMap}; +use syntax::codemap::Span; +use syntax::parse::token; +use syntax::ast; +use syntax::attr; +use syntax::visit; +use syntax::visit::Visitor; +use syntax::attr::AttrMetaMethods; + +struct MacroLoader<'a> { + sess: &'a Session, + span_whitelist: HashSet, + reader: CrateReader<'a>, + macros: Vec, +} + +impl<'a> MacroLoader<'a> { + fn new(sess: &'a Session, cstore: &'a CStore) -> MacroLoader<'a> { + MacroLoader { + sess: sess, + span_whitelist: HashSet::new(), + reader: CrateReader::new(sess, cstore), + macros: vec![], + } + } +} + +pub fn call_bad_macro_reexport(a: &Session, b: Span) { + span_err!(a, b, E0467, "bad macro reexport"); +} + +/// Read exported macros. +pub fn read_macro_defs(sess: &Session, cstore: &CStore, krate: &ast::Crate) + -> Vec +{ + let mut loader = MacroLoader::new(sess, cstore); + + // We need to error on `#[macro_use] extern crate` when it isn't at the + // crate root, because `$crate` won't work properly. Identify these by + // spans, because the crate map isn't set up yet. + for item in &krate.module.items { + if let ast::ItemExternCrate(_) = item.node { + loader.span_whitelist.insert(item.span); + } + } + + visit::walk_crate(&mut loader, krate); + + loader.macros +} + +pub type MacroSelection = HashMap; + +// note that macros aren't expanded yet, and therefore macros can't add macro imports. +impl<'a, 'v> Visitor<'v> for MacroLoader<'a> { + fn visit_item(&mut self, item: &ast::Item) { + // We're only interested in `extern crate`. + match item.node { + ast::ItemExternCrate(_) => {} + _ => { + visit::walk_item(self, item); + return; + } + } + + // Parse the attributes relating to macros. + let mut import = Some(HashMap::new()); // None => load all + let mut reexport = HashMap::new(); + + for attr in &item.attrs { + let mut used = true; + match &attr.name()[..] { + "macro_use" => { + let names = attr.meta_item_list(); + if names.is_none() { + // no names => load all + import = None; + } + if let (Some(sel), Some(names)) = (import.as_mut(), names) { + for attr in names { + if let ast::MetaWord(ref name) = attr.node { + sel.insert(name.clone(), attr.span); + } else { + span_err!(self.sess, attr.span, E0466, "bad macro import"); + } + } + } + } + "macro_reexport" => { + let names = match attr.meta_item_list() { + Some(names) => names, + None => { + call_bad_macro_reexport(self.sess, attr.span); + continue; + } + }; + + for attr in names { + if let ast::MetaWord(ref name) = attr.node { + reexport.insert(name.clone(), attr.span); + } else { + call_bad_macro_reexport(self.sess, attr.span); + } + } + } + _ => used = false, + } + if used { + attr::mark_used(attr); + } + } + + self.load_macros(item, import, reexport) + } + + fn visit_mac(&mut self, _: &ast::Mac) { + // bummer... can't see macro imports inside macros. + // do nothing. + } +} + +impl<'a> MacroLoader<'a> { + fn load_macros<'b>(&mut self, + vi: &ast::Item, + import: Option, + reexport: MacroSelection) { + if let Some(sel) = import.as_ref() { + if sel.is_empty() && reexport.is_empty() { + return; + } + } + + if !self.span_whitelist.contains(&vi.span) { + span_err!(self.sess, vi.span, E0468, + "an `extern crate` loading macros must be at the crate root"); + return; + } + + let macros = self.reader.read_exported_macros(vi); + let mut seen = HashSet::new(); + + for mut def in macros { + let name = def.ident.name.as_str(); + + def.use_locally = match import.as_ref() { + None => true, + Some(sel) => sel.contains_key(&name), + }; + def.export = reexport.contains_key(&name); + def.allow_internal_unstable = attr::contains_name(&def.attrs, + "allow_internal_unstable"); + debug!("load_macros: loaded: {:?}", def); + self.macros.push(def); + seen.insert(name); + } + + if let Some(sel) = import.as_ref() { + for (name, span) in sel { + if !seen.contains(&name) { + span_err!(self.sess, *span, E0469, + "imported macro not found"); + } + } + } + + for (name, span) in &reexport { + if !seen.contains(&name) { + span_err!(self.sess, *span, E0470, + "reexported macro not found"); + } + } + } +} diff --git a/src/librustc_metadata/macros.rs b/src/librustc_metadata/macros.rs new file mode 100644 index 00000000000..ed764ebd9f9 --- /dev/null +++ b/src/librustc_metadata/macros.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! enum_from_u32 { + ($(#[$attr:meta])* pub enum $name:ident { + $($variant:ident = $e:expr,)* + }) => { + $(#[$attr])* + pub enum $name { + $($variant = $e),* + } + + impl $name { + pub fn from_u32(u: u32) -> Option<$name> { + $(if u == $name::$variant as u32 { + return Some($name::$variant) + })* + None + } + } + }; + ($(#[$attr:meta])* pub enum $name:ident { + $($variant:ident,)* + }) => { + $(#[$attr])* + pub enum $name { + $($variant,)* + } + + impl $name { + pub fn from_u32(u: u32) -> Option<$name> { + $(if u == $name::$variant as u32 { + return Some($name::$variant) + })* + None + } + } + } +} diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs new file mode 100644 index 00000000000..d03af6b6722 --- /dev/null +++ b/src/librustc_metadata/tydecode.rs @@ -0,0 +1,711 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// Type decoding + +// tjc note: Would be great to have a `match check` macro equivalent +// for some of these + +#![allow(non_camel_case_types)] + +use rustc_front::hir; + +use middle::def_id::{DefId, DefIndex}; +use middle::region; +use middle::subst; +use middle::subst::VecPerParamSpace; +use middle::ty::{self, ToPredicate, Ty, HasTypeFlags}; + +use rbml; +use std::str; +use syntax::abi; +use syntax::ast; +use syntax::parse::token; + +// Compact string representation for Ty values. API TyStr & +// parse_from_str. Extra parameters are for converting to/from def_ids in the +// data buffer. Whatever format you choose should not contain pipe characters. + +pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId; + +pub struct TyDecoder<'a, 'tcx: 'a> { + data: &'a [u8], + krate: ast::CrateNum, + pos: usize, + tcx: &'a ty::ctxt<'tcx>, + conv_def_id: DefIdConvert<'a>, +} + +impl<'a,'tcx> TyDecoder<'a,'tcx> { + pub fn with_doc(tcx: &'a ty::ctxt<'tcx>, + crate_num: ast::CrateNum, + doc: rbml::Doc<'a>, + conv: DefIdConvert<'a>) + -> TyDecoder<'a,'tcx> { + TyDecoder::new(doc.data, crate_num, doc.start, tcx, conv) + } + + pub fn new(data: &'a [u8], + crate_num: ast::CrateNum, + pos: usize, + tcx: &'a ty::ctxt<'tcx>, + conv: DefIdConvert<'a>) + -> TyDecoder<'a, 'tcx> { + TyDecoder { + data: data, + krate: crate_num, + pos: pos, + tcx: tcx, + conv_def_id: conv, + } + } + + fn peek(&self) -> char { + self.data[self.pos] as char + } + + fn next(&mut self) -> char { + let ch = self.data[self.pos] as char; + self.pos = self.pos + 1; + return ch; + } + + fn next_byte(&mut self) -> u8 { + let b = self.data[self.pos]; + self.pos = self.pos + 1; + return b; + } + + fn scan(&mut self, mut is_last: F) -> &'a [u8] + where F: FnMut(char) -> bool, + { + let start_pos = self.pos; + debug!("scan: '{}' (start)", self.data[self.pos] as char); + while !is_last(self.data[self.pos] as char) { + self.pos += 1; + debug!("scan: '{}'", self.data[self.pos] as char); + } + let end_pos = self.pos; + self.pos += 1; + return &self.data[start_pos..end_pos]; + } + + fn parse_vuint(&mut self) -> usize { + let res = rbml::reader::vuint_at(self.data, self.pos).unwrap(); + self.pos = res.next; + res.val + } + + fn parse_name(&mut self, last: char) -> ast::Name { + fn is_last(b: char, c: char) -> bool { return c == b; } + let bytes = self.scan(|a| is_last(last, a)); + token::intern(str::from_utf8(bytes).unwrap()) + } + + fn parse_size(&mut self) -> Option { + assert_eq!(self.next(), '/'); + + if self.peek() == '|' { + assert_eq!(self.next(), '|'); + None + } else { + let n = self.parse_uint(); + assert_eq!(self.next(), '|'); + Some(n) + } + } + + fn parse_vec_per_param_space(&mut self, mut f: F) -> VecPerParamSpace where + F: FnMut(&mut TyDecoder<'a, 'tcx>) -> T, + { + let mut r = VecPerParamSpace::empty(); + for &space in &subst::ParamSpace::all() { + assert_eq!(self.next(), '['); + while self.peek() != ']' { + r.push(space, f(self)); + } + assert_eq!(self.next(), ']'); + } + r + } + + pub fn parse_substs(&mut self) -> subst::Substs<'tcx> { + let regions = self.parse_region_substs(); + let types = self.parse_vec_per_param_space(|this| this.parse_ty()); + subst::Substs { types: types, regions: regions } + } + + fn parse_region_substs(&mut self) -> subst::RegionSubsts { + match self.next() { + 'e' => subst::ErasedRegions, + 'n' => { + subst::NonerasedRegions( + self.parse_vec_per_param_space(|this| this.parse_region())) + } + _ => panic!("parse_bound_region: bad input") + } + } + + fn parse_bound_region(&mut self) -> ty::BoundRegion { + match self.next() { + 'a' => { + let id = self.parse_u32(); + assert_eq!(self.next(), '|'); + ty::BrAnon(id) + } + '[' => { + let def = self.parse_def(); + let name = token::intern(&self.parse_str(']')); + ty::BrNamed(def, name) + } + 'f' => { + let id = self.parse_u32(); + assert_eq!(self.next(), '|'); + ty::BrFresh(id) + } + 'e' => ty::BrEnv, + _ => panic!("parse_bound_region: bad input") + } + } + + pub fn parse_region(&mut self) -> ty::Region { + match self.next() { + 'b' => { + assert_eq!(self.next(), '['); + let id = ty::DebruijnIndex::new(self.parse_u32()); + assert_eq!(self.next(), '|'); + let br = self.parse_bound_region(); + assert_eq!(self.next(), ']'); + ty::ReLateBound(id, br) + } + 'B' => { + assert_eq!(self.next(), '['); + let def_id = self.parse_def(); + let space = self.parse_param_space(); + assert_eq!(self.next(), '|'); + let index = self.parse_u32(); + assert_eq!(self.next(), '|'); + let name = token::intern(&self.parse_str(']')); + ty::ReEarlyBound(ty::EarlyBoundRegion { + def_id: def_id, + space: space, + index: index, + name: name + }) + } + 'f' => { + assert_eq!(self.next(), '['); + let scope = self.parse_scope(); + assert_eq!(self.next(), '|'); + let br = self.parse_bound_region(); + assert_eq!(self.next(), ']'); + ty::ReFree(ty::FreeRegion { scope: scope, + bound_region: br}) + } + 's' => { + let scope = self.parse_scope(); + assert_eq!(self.next(), '|'); + ty::ReScope(scope) + } + 't' => { + ty::ReStatic + } + 'e' => { + ty::ReStatic + } + _ => panic!("parse_region: bad input") + } + } + + fn parse_scope(&mut self) -> region::CodeExtent { + self.tcx.region_maps.bogus_code_extent(match self.next() { + // This creates scopes with the wrong NodeId. This isn't + // actually a problem because scopes only exist *within* + // functions, and functions aren't loaded until trans which + // doesn't care about regions. + // + // May still be worth fixing though. + 'P' => { + assert_eq!(self.next(), '['); + let fn_id = self.parse_uint() as ast::NodeId; + assert_eq!(self.next(), '|'); + let body_id = self.parse_uint() as ast::NodeId; + assert_eq!(self.next(), ']'); + region::CodeExtentData::ParameterScope { + fn_id: fn_id, body_id: body_id + } + } + 'M' => { + let node_id = self.parse_uint() as ast::NodeId; + region::CodeExtentData::Misc(node_id) + } + 'D' => { + let node_id = self.parse_uint() as ast::NodeId; + region::CodeExtentData::DestructionScope(node_id) + } + 'B' => { + assert_eq!(self.next(), '['); + let node_id = self.parse_uint() as ast::NodeId; + assert_eq!(self.next(), '|'); + let first_stmt_index = self.parse_u32(); + assert_eq!(self.next(), ']'); + let block_remainder = region::BlockRemainder { + block: node_id, first_statement_index: first_stmt_index, + }; + region::CodeExtentData::Remainder(block_remainder) + } + _ => panic!("parse_scope: bad input") + }) + } + + fn parse_opt(&mut self, f: F) -> Option + where F: FnOnce(&mut TyDecoder<'a, 'tcx>) -> T, + { + match self.next() { + 'n' => None, + 's' => Some(f(self)), + _ => panic!("parse_opt: bad input") + } + } + + fn parse_str(&mut self, term: char) -> String { + let mut result = String::new(); + while self.peek() != term { + unsafe { + result.as_mut_vec().push_all(&[self.next_byte()]) + } + } + self.next(); + result + } + + pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> { + let def = self.parse_def(); + let substs = self.tcx.mk_substs(self.parse_substs()); + ty::TraitRef {def_id: def, substs: substs} + } + + pub fn parse_ty(&mut self) -> Ty<'tcx> { + let tcx = self.tcx; + match self.next() { + 'b' => return tcx.types.bool, + 'i' => { /* eat the s of is */ self.next(); return tcx.types.isize }, + 'u' => { /* eat the s of us */ self.next(); return tcx.types.usize }, + 'M' => { + match self.next() { + 'b' => return tcx.types.u8, + 'w' => return tcx.types.u16, + 'l' => return tcx.types.u32, + 'd' => return tcx.types.u64, + 'B' => return tcx.types.i8, + 'W' => return tcx.types.i16, + 'L' => return tcx.types.i32, + 'D' => return tcx.types.i64, + 'f' => return tcx.types.f32, + 'F' => return tcx.types.f64, + _ => panic!("parse_ty: bad numeric type") + } + } + 'c' => return tcx.types.char, + 't' => { + assert_eq!(self.next(), '['); + let did = self.parse_def(); + let substs = self.parse_substs(); + assert_eq!(self.next(), ']'); + let def = self.tcx.lookup_adt_def(did); + return tcx.mk_enum(def, self.tcx.mk_substs(substs)); + } + 'x' => { + assert_eq!(self.next(), '['); + let trait_ref = ty::Binder(self.parse_trait_ref()); + let bounds = self.parse_existential_bounds(); + assert_eq!(self.next(), ']'); + return tcx.mk_trait(trait_ref, bounds); + } + 'p' => { + assert_eq!(self.next(), '['); + let index = self.parse_u32(); + assert_eq!(self.next(), '|'); + let space = self.parse_param_space(); + assert_eq!(self.next(), '|'); + let name = token::intern(&self.parse_str(']')); + return tcx.mk_param(space, index, name); + } + '~' => return tcx.mk_box(self.parse_ty()), + '*' => return tcx.mk_ptr(self.parse_mt()), + '&' => { + let r = self.parse_region(); + let mt = self.parse_mt(); + return tcx.mk_ref(tcx.mk_region(r), mt); + } + 'V' => { + let t = self.parse_ty(); + return match self.parse_size() { + Some(n) => tcx.mk_array(t, n), + None => tcx.mk_slice(t) + }; + } + 'v' => { + return tcx.mk_str(); + } + 'T' => { + assert_eq!(self.next(), '['); + let mut params = Vec::new(); + while self.peek() != ']' { params.push(self.parse_ty()); } + self.pos = self.pos + 1; + return tcx.mk_tup(params); + } + 'F' => { + let def_id = self.parse_def(); + return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(self.parse_bare_fn_ty())); + } + 'G' => { + return tcx.mk_fn(None, tcx.mk_bare_fn(self.parse_bare_fn_ty())); + } + '#' => { + // This is a hacky little caching scheme. The idea is that if we encode + // the same type twice, the second (and third, and fourth...) time we will + // just write `#123`, where `123` is the offset in the metadata of the + // first appearance. Now when we are *decoding*, if we see a `#123`, we + // can first check a cache (`tcx.rcache`) for that offset. If we find something, + // we return it (modulo closure types, see below). But if not, then we + // jump to offset 123 and read the type from there. + + let pos = self.parse_vuint(); + let key = ty::CReaderCacheKey { cnum: self.krate, pos: pos }; + match tcx.rcache.borrow().get(&key).cloned() { + Some(tt) => { + // If there is a closure buried in the type some where, then we + // need to re-convert any def ids (see case 'k', below). That means + // we can't reuse the cached version. + if !tt.has_closure_types() { + return tt; + } + } + None => {} + } + + let mut substate = TyDecoder::new(self.data, + self.krate, + pos, + self.tcx, + self.conv_def_id); + let tt = substate.parse_ty(); + tcx.rcache.borrow_mut().insert(key, tt); + return tt; + } + '\"' => { + let _ = self.parse_def(); + let inner = self.parse_ty(); + inner + } + 'a' => { + assert_eq!(self.next(), '['); + let did = self.parse_def(); + let substs = self.parse_substs(); + assert_eq!(self.next(), ']'); + let def = self.tcx.lookup_adt_def(did); + return self.tcx.mk_struct(def, self.tcx.mk_substs(substs)); + } + 'k' => { + assert_eq!(self.next(), '['); + let did = self.parse_def(); + let substs = self.parse_substs(); + let mut tys = vec![]; + while self.peek() != '.' { + tys.push(self.parse_ty()); + } + assert_eq!(self.next(), '.'); + assert_eq!(self.next(), ']'); + return self.tcx.mk_closure(did, self.tcx.mk_substs(substs), tys); + } + 'P' => { + assert_eq!(self.next(), '['); + let trait_ref = self.parse_trait_ref(); + let name = token::intern(&self.parse_str(']')); + return tcx.mk_projection(trait_ref, name); + } + 'e' => { + return tcx.types.err; + } + c => { panic!("unexpected char in type string: {}", c);} + } + } + + fn parse_mutability(&mut self) -> hir::Mutability { + match self.peek() { + 'm' => { self.next(); hir::MutMutable } + _ => { hir::MutImmutable } + } + } + + fn parse_mt(&mut self) -> ty::TypeAndMut<'tcx> { + let m = self.parse_mutability(); + ty::TypeAndMut { ty: self.parse_ty(), mutbl: m } + } + + fn parse_def(&mut self) -> DefId { + let def_id = parse_defid(self.scan(|c| c == '|')); + return (self.conv_def_id)(def_id); + } + + fn parse_uint(&mut self) -> usize { + let mut n = 0; + loop { + let cur = self.peek(); + if cur < '0' || cur > '9' { return n; } + self.pos = self.pos + 1; + n *= 10; + n += (cur as usize) - ('0' as usize); + }; + } + + fn parse_u32(&mut self) -> u32 { + let n = self.parse_uint(); + let m = n as u32; + assert_eq!(m as usize, n); + m + } + + fn parse_param_space(&mut self) -> subst::ParamSpace { + subst::ParamSpace::from_uint(self.parse_uint()) + } + + fn parse_abi_set(&mut self) -> abi::Abi { + assert_eq!(self.next(), '['); + let bytes = self.scan(|c| c == ']'); + let abi_str = str::from_utf8(bytes).unwrap(); + abi::lookup(&abi_str[..]).expect(abi_str) + } + + pub fn parse_closure_ty(&mut self) -> ty::ClosureTy<'tcx> { + let unsafety = parse_unsafety(self.next()); + let sig = self.parse_sig(); + let abi = self.parse_abi_set(); + ty::ClosureTy { + unsafety: unsafety, + sig: sig, + abi: abi, + } + } + + pub fn parse_bare_fn_ty(&mut self) -> ty::BareFnTy<'tcx> { + let unsafety = parse_unsafety(self.next()); + let abi = self.parse_abi_set(); + let sig = self.parse_sig(); + ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: sig + } + } + + fn parse_sig(&mut self) -> ty::PolyFnSig<'tcx> { + assert_eq!(self.next(), '['); + let mut inputs = Vec::new(); + while self.peek() != ']' { + inputs.push(self.parse_ty()); + } + self.pos += 1; // eat the ']' + let variadic = match self.next() { + 'V' => true, + 'N' => false, + r => panic!(format!("bad variadic: {}", r)), + }; + let output = match self.peek() { + 'z' => { + self.pos += 1; + ty::FnDiverging + } + _ => ty::FnConverging(self.parse_ty()) + }; + ty::Binder(ty::FnSig {inputs: inputs, + output: output, + variadic: variadic}) + } + + pub fn parse_predicate(&mut self) -> ty::Predicate<'tcx> { + match self.next() { + 't' => ty::Binder(self.parse_trait_ref()).to_predicate(), + 'e' => ty::Binder(ty::EquatePredicate(self.parse_ty(), + self.parse_ty())).to_predicate(), + 'r' => ty::Binder(ty::OutlivesPredicate(self.parse_region(), + self.parse_region())).to_predicate(), + 'o' => ty::Binder(ty::OutlivesPredicate(self.parse_ty(), + self.parse_region())).to_predicate(), + 'p' => ty::Binder(self.parse_projection_predicate()).to_predicate(), + 'w' => ty::Predicate::WellFormed(self.parse_ty()), + 'O' => { + let def_id = self.parse_def(); + assert_eq!(self.next(), '|'); + ty::Predicate::ObjectSafe(def_id) + } + c => panic!("Encountered invalid character in metadata: {}", c) + } + } + + fn parse_projection_predicate(&mut self) -> ty::ProjectionPredicate<'tcx> { + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: self.parse_trait_ref(), + item_name: token::intern(&self.parse_str('|')), + }, + ty: self.parse_ty(), + } + } + + pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { + let name = self.parse_name(':'); + let def_id = self.parse_def(); + let space = self.parse_param_space(); + assert_eq!(self.next(), '|'); + let index = self.parse_u32(); + assert_eq!(self.next(), '|'); + let default_def_id = self.parse_def(); + let default = self.parse_opt(|this| this.parse_ty()); + let object_lifetime_default = self.parse_object_lifetime_default(); + + ty::TypeParameterDef { + name: name, + def_id: def_id, + space: space, + index: index, + default_def_id: default_def_id, + default: default, + object_lifetime_default: object_lifetime_default, + } + } + + pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef { + let name = self.parse_name(':'); + let def_id = self.parse_def(); + let space = self.parse_param_space(); + assert_eq!(self.next(), '|'); + let index = self.parse_u32(); + assert_eq!(self.next(), '|'); + let mut bounds = vec![]; + loop { + match self.next() { + 'R' => bounds.push(self.parse_region()), + '.' => { break; } + c => { + panic!("parse_region_param_def: bad bounds ('{}')", c) + } + } + } + ty::RegionParameterDef { + name: name, + def_id: def_id, + space: space, + index: index, + bounds: bounds + } + } + + + fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault { + match self.next() { + 'a' => ty::ObjectLifetimeDefault::Ambiguous, + 'b' => ty::ObjectLifetimeDefault::BaseDefault, + 's' => { + let region = self.parse_region(); + ty::ObjectLifetimeDefault::Specific(region) + } + _ => panic!("parse_object_lifetime_default: bad input") + } + } + + pub fn parse_existential_bounds(&mut self) -> ty::ExistentialBounds<'tcx> { + let builtin_bounds = self.parse_builtin_bounds(); + let region_bound = self.parse_region(); + let mut projection_bounds = Vec::new(); + + loop { + match self.next() { + 'P' => { + projection_bounds.push(ty::Binder(self.parse_projection_predicate())); + } + '.' => { break; } + c => { + panic!("parse_bounds: bad bounds ('{}')", c) + } + } + } + + ty::ExistentialBounds::new( + region_bound, builtin_bounds, projection_bounds) + } + + fn parse_builtin_bounds(&mut self) -> ty::BuiltinBounds { + let mut builtin_bounds = ty::BuiltinBounds::empty(); + loop { + match self.next() { + 'S' => { + builtin_bounds.insert(ty::BoundSend); + } + 'Z' => { + builtin_bounds.insert(ty::BoundSized); + } + 'P' => { + builtin_bounds.insert(ty::BoundCopy); + } + 'T' => { + builtin_bounds.insert(ty::BoundSync); + } + '.' => { + return builtin_bounds; + } + c => { + panic!("parse_bounds: bad builtin bounds ('{}')", c) + } + } + } + } +} + +// Rust metadata parsing +fn parse_defid(buf: &[u8]) -> DefId { + let mut colon_idx = 0; + let len = buf.len(); + while colon_idx < len && buf[colon_idx] != ':' as u8 { colon_idx += 1; } + if colon_idx == len { + error!("didn't find ':' when parsing def id"); + panic!(); + } + + let crate_part = &buf[0..colon_idx]; + let def_part = &buf[colon_idx + 1..len]; + + let crate_num = match str::from_utf8(crate_part).ok().and_then(|s| { + s.parse::().ok() + }) { + Some(cn) => cn as ast::CrateNum, + None => panic!("internal error: parse_defid: crate number expected, found {:?}", + crate_part) + }; + let def_num = match str::from_utf8(def_part).ok().and_then(|s| { + s.parse::().ok() + }) { + Some(dn) => dn, + None => panic!("internal error: parse_defid: id expected, found {:?}", + def_part) + }; + let index = DefIndex::new(def_num); + DefId { krate: crate_num, index: index } +} + +fn parse_unsafety(c: char) -> hir::Unsafety { + match c { + 'u' => hir::Unsafety::Unsafe, + 'n' => hir::Unsafety::Normal, + _ => panic!("parse_unsafety: bad unsafety {}", c) + } +} diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs new file mode 100644 index 00000000000..bc1edd5c767 --- /dev/null +++ b/src/librustc_metadata/tyencode.rs @@ -0,0 +1,479 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Type encoding + +#![allow(unused_must_use)] // as with encoding, everything is a no-fail MemWriter +#![allow(non_camel_case_types)] + +use std::cell::RefCell; +use std::io::Cursor; +use std::io::prelude::*; + +use middle::def_id::DefId; +use middle::region; +use middle::subst; +use middle::subst::VecPerParamSpace; +use middle::ty::ParamTy; +use middle::ty::{self, Ty}; +use rustc::util::nodemap::FnvHashMap; + +use rustc_front::hir; + +use syntax::abi::Abi; +use syntax::ast; +use syntax::diagnostic::SpanHandler; + +use rbml::writer::{self, Encoder}; + +macro_rules! mywrite { ($w:expr, $($arg:tt)*) => ({ write!($w.writer, $($arg)*); }) } + +pub struct ctxt<'a, 'tcx: 'a> { + pub diag: &'a SpanHandler, + // Def -> str Callback: + pub ds: fn(DefId) -> String, + // The type context. + pub tcx: &'a ty::ctxt<'tcx>, + pub abbrevs: &'a abbrev_map<'tcx> +} + +// Compact string representation for Ty values. API TyStr & parse_from_str. +// Extra parameters are for converting to/from def_ids in the string rep. +// Whatever format you choose should not contain pipe characters. +pub struct ty_abbrev { + s: Vec +} + +pub type abbrev_map<'tcx> = RefCell, ty_abbrev>>; + +pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { + match cx.abbrevs.borrow_mut().get(&t) { + Some(a) => { w.writer.write_all(&a.s); return; } + None => {} + } + + // type abbreviations needs a stable position + let pos = w.mark_stable_position(); + + match t.sty { + ty::TyBool => mywrite!(w, "b"), + ty::TyChar => mywrite!(w, "c"), + ty::TyInt(t) => { + match t { + ast::TyIs => mywrite!(w, "is"), + ast::TyI8 => mywrite!(w, "MB"), + ast::TyI16 => mywrite!(w, "MW"), + ast::TyI32 => mywrite!(w, "ML"), + ast::TyI64 => mywrite!(w, "MD") + } + } + ty::TyUint(t) => { + match t { + ast::TyUs => mywrite!(w, "us"), + ast::TyU8 => mywrite!(w, "Mb"), + ast::TyU16 => mywrite!(w, "Mw"), + ast::TyU32 => mywrite!(w, "Ml"), + ast::TyU64 => mywrite!(w, "Md") + } + } + ty::TyFloat(t) => { + match t { + ast::TyF32 => mywrite!(w, "Mf"), + ast::TyF64 => mywrite!(w, "MF"), + } + } + ty::TyEnum(def, substs) => { + mywrite!(w, "t[{}|", (cx.ds)(def.did)); + enc_substs(w, cx, substs); + mywrite!(w, "]"); + } + ty::TyTrait(box ty::TraitTy { ref principal, + ref bounds }) => { + mywrite!(w, "x["); + enc_trait_ref(w, cx, principal.0); + enc_existential_bounds(w, cx, bounds); + mywrite!(w, "]"); + } + ty::TyTuple(ref ts) => { + mywrite!(w, "T["); + for t in ts { enc_ty(w, cx, *t); } + mywrite!(w, "]"); + } + ty::TyBox(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); } + ty::TyRawPtr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); } + ty::TyRef(r, mt) => { + mywrite!(w, "&"); + enc_region(w, cx, *r); + enc_mt(w, cx, mt); + } + ty::TyArray(t, sz) => { + mywrite!(w, "V"); + enc_ty(w, cx, t); + mywrite!(w, "/{}|", sz); + } + ty::TySlice(t) => { + mywrite!(w, "V"); + enc_ty(w, cx, t); + mywrite!(w, "/|"); + } + ty::TyStr => { + mywrite!(w, "v"); + } + ty::TyBareFn(Some(def_id), f) => { + mywrite!(w, "F"); + mywrite!(w, "{}|", (cx.ds)(def_id)); + enc_bare_fn_ty(w, cx, f); + } + ty::TyBareFn(None, f) => { + mywrite!(w, "G"); + enc_bare_fn_ty(w, cx, f); + } + ty::TyInfer(_) => { + cx.diag.handler().bug("cannot encode inference variable types"); + } + ty::TyParam(ParamTy {space, idx, name}) => { + mywrite!(w, "p[{}|{}|{}]", idx, space.to_uint(), name) + } + ty::TyStruct(def, substs) => { + mywrite!(w, "a[{}|", (cx.ds)(def.did)); + enc_substs(w, cx, substs); + mywrite!(w, "]"); + } + ty::TyClosure(def, ref substs) => { + mywrite!(w, "k[{}|", (cx.ds)(def)); + enc_substs(w, cx, &substs.func_substs); + for ty in &substs.upvar_tys { + enc_ty(w, cx, ty); + } + mywrite!(w, "."); + mywrite!(w, "]"); + } + ty::TyProjection(ref data) => { + mywrite!(w, "P["); + enc_trait_ref(w, cx, data.trait_ref); + mywrite!(w, "{}]", data.item_name); + } + ty::TyError => { + mywrite!(w, "e"); + } + } + + let end = w.mark_stable_position(); + let len = end - pos; + + let buf: &mut [u8] = &mut [0; 16]; // vuint < 15 bytes + let mut abbrev = Cursor::new(buf); + abbrev.write_all(b"#"); + writer::write_vuint(&mut abbrev, pos as usize); + + cx.abbrevs.borrow_mut().insert(t, ty_abbrev { + s: if abbrev.position() < len { + abbrev.get_ref()[..abbrev.position() as usize].to_owned() + } else { + // if the abbreviation is longer than the real type, + // don't use #-notation. However, insert it here so + // other won't have to `mark_stable_position` + w.writer.get_ref()[pos as usize..end as usize].to_owned() + } + }); +} + +fn enc_mutability(w: &mut Encoder, mt: hir::Mutability) { + match mt { + hir::MutImmutable => (), + hir::MutMutable => mywrite!(w, "m"), + } +} + +fn enc_mt<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, + mt: ty::TypeAndMut<'tcx>) { + enc_mutability(w, mt.mutbl); + enc_ty(w, cx, mt.ty); +} + +fn enc_opt(w: &mut Encoder, t: Option, enc_f: F) where + F: FnOnce(&mut Encoder, T), +{ + match t { + None => mywrite!(w, "n"), + Some(v) => { + mywrite!(w, "s"); + enc_f(w, v); + } + } +} + +fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut Encoder, + cx: &ctxt<'a, 'tcx>, + v: &VecPerParamSpace, + mut op: F) where + F: FnMut(&mut Encoder, &ctxt<'a, 'tcx>, &T), +{ + for &space in &subst::ParamSpace::all() { + mywrite!(w, "["); + for t in v.get_slice(space) { + op(w, cx, t); + } + mywrite!(w, "]"); + } +} + +pub fn enc_substs<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, + substs: &subst::Substs<'tcx>) { + enc_region_substs(w, cx, &substs.regions); + enc_vec_per_param_space(w, cx, &substs.types, + |w, cx, &ty| enc_ty(w, cx, ty)); +} + +fn enc_region_substs(w: &mut Encoder, cx: &ctxt, substs: &subst::RegionSubsts) { + match *substs { + subst::ErasedRegions => { + mywrite!(w, "e"); + } + subst::NonerasedRegions(ref regions) => { + mywrite!(w, "n"); + enc_vec_per_param_space(w, cx, regions, + |w, cx, &r| enc_region(w, cx, r)); + } + } +} + +pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { + match r { + ty::ReLateBound(id, br) => { + mywrite!(w, "b[{}|", id.depth); + enc_bound_region(w, cx, br); + mywrite!(w, "]"); + } + ty::ReEarlyBound(ref data) => { + mywrite!(w, "B[{}|{}|{}|{}]", + (cx.ds)(data.def_id), + data.space.to_uint(), + data.index, + data.name); + } + ty::ReFree(ref fr) => { + mywrite!(w, "f["); + enc_scope(w, cx, fr.scope); + mywrite!(w, "|"); + enc_bound_region(w, cx, fr.bound_region); + mywrite!(w, "]"); + } + ty::ReScope(scope) => { + mywrite!(w, "s"); + enc_scope(w, cx, scope); + mywrite!(w, "|"); + } + ty::ReStatic => { + mywrite!(w, "t"); + } + ty::ReEmpty => { + mywrite!(w, "e"); + } + ty::ReVar(_) | ty::ReSkolemized(..) => { + // these should not crop up after typeck + cx.diag.handler().bug("cannot encode region variables"); + } + } +} + +fn enc_scope(w: &mut Encoder, cx: &ctxt, scope: region::CodeExtent) { + match cx.tcx.region_maps.code_extent_data(scope) { + region::CodeExtentData::ParameterScope { + fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id), + region::CodeExtentData::Misc(node_id) => mywrite!(w, "M{}", node_id), + region::CodeExtentData::Remainder(region::BlockRemainder { + block: b, first_statement_index: i }) => mywrite!(w, "B[{}|{}]", b, i), + region::CodeExtentData::DestructionScope(node_id) => mywrite!(w, "D{}", node_id), + } +} + +fn enc_bound_region(w: &mut Encoder, cx: &ctxt, br: ty::BoundRegion) { + match br { + ty::BrAnon(idx) => { + mywrite!(w, "a{}|", idx); + } + ty::BrNamed(d, name) => { + mywrite!(w, "[{}|{}]", + (cx.ds)(d), + name); + } + ty::BrFresh(id) => { + mywrite!(w, "f{}|", id); + } + ty::BrEnv => { + mywrite!(w, "e|"); + } + } +} + +pub fn enc_trait_ref<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, + s: ty::TraitRef<'tcx>) { + mywrite!(w, "{}|", (cx.ds)(s.def_id)); + enc_substs(w, cx, s.substs); +} + +fn enc_unsafety(w: &mut Encoder, p: hir::Unsafety) { + match p { + hir::Unsafety::Normal => mywrite!(w, "n"), + hir::Unsafety::Unsafe => mywrite!(w, "u"), + } +} + +fn enc_abi(w: &mut Encoder, abi: Abi) { + mywrite!(w, "["); + mywrite!(w, "{}", abi.name()); + mywrite!(w, "]") +} + +pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, + ft: &ty::BareFnTy<'tcx>) { + enc_unsafety(w, ft.unsafety); + enc_abi(w, ft.abi); + enc_fn_sig(w, cx, &ft.sig); +} + +pub fn enc_closure_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, + ft: &ty::ClosureTy<'tcx>) { + enc_unsafety(w, ft.unsafety); + enc_fn_sig(w, cx, &ft.sig); + enc_abi(w, ft.abi); +} + +fn enc_fn_sig<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, + fsig: &ty::PolyFnSig<'tcx>) { + mywrite!(w, "["); + for ty in &fsig.0.inputs { + enc_ty(w, cx, *ty); + } + mywrite!(w, "]"); + if fsig.0.variadic { + mywrite!(w, "V"); + } else { + mywrite!(w, "N"); + } + match fsig.0.output { + ty::FnConverging(result_type) => { + enc_ty(w, cx, result_type); + } + ty::FnDiverging => { + mywrite!(w, "z"); + } + } +} + +pub fn enc_builtin_bounds(w: &mut Encoder, _cx: &ctxt, bs: &ty::BuiltinBounds) { + for bound in bs { + match bound { + ty::BoundSend => mywrite!(w, "S"), + ty::BoundSized => mywrite!(w, "Z"), + ty::BoundCopy => mywrite!(w, "P"), + ty::BoundSync => mywrite!(w, "T"), + } + } + + mywrite!(w, "."); +} + +pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder, + cx: &ctxt<'a,'tcx>, + bs: &ty::ExistentialBounds<'tcx>) { + enc_builtin_bounds(w, cx, &bs.builtin_bounds); + + enc_region(w, cx, bs.region_bound); + + for tp in &bs.projection_bounds { + mywrite!(w, "P"); + enc_projection_predicate(w, cx, &tp.0); + } + + mywrite!(w, "."); +} + +pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, + v: &ty::TypeParameterDef<'tcx>) { + mywrite!(w, "{}:{}|{}|{}|{}|", + v.name, (cx.ds)(v.def_id), + v.space.to_uint(), v.index, (cx.ds)(v.default_def_id)); + enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); + enc_object_lifetime_default(w, cx, v.object_lifetime_default); +} + +pub fn enc_region_param_def(w: &mut Encoder, cx: &ctxt, + v: &ty::RegionParameterDef) { + mywrite!(w, "{}:{}|{}|{}|", + v.name, (cx.ds)(v.def_id), + v.space.to_uint(), v.index); + for &r in &v.bounds { + mywrite!(w, "R"); + enc_region(w, cx, r); + } + mywrite!(w, "."); +} + +fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder, + cx: &ctxt<'a, 'tcx>, + default: ty::ObjectLifetimeDefault) +{ + match default { + ty::ObjectLifetimeDefault::Ambiguous => mywrite!(w, "a"), + ty::ObjectLifetimeDefault::BaseDefault => mywrite!(w, "b"), + ty::ObjectLifetimeDefault::Specific(r) => { + mywrite!(w, "s"); + enc_region(w, cx, r); + } + } +} + +pub fn enc_predicate<'a, 'tcx>(w: &mut Encoder, + cx: &ctxt<'a, 'tcx>, + p: &ty::Predicate<'tcx>) +{ + match *p { + ty::Predicate::Trait(ref trait_ref) => { + mywrite!(w, "t"); + enc_trait_ref(w, cx, trait_ref.0.trait_ref); + } + ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => { + mywrite!(w, "e"); + enc_ty(w, cx, a); + enc_ty(w, cx, b); + } + ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { + mywrite!(w, "r"); + enc_region(w, cx, a); + enc_region(w, cx, b); + } + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { + mywrite!(w, "o"); + enc_ty(w, cx, a); + enc_region(w, cx, b); + } + ty::Predicate::Projection(ty::Binder(ref data)) => { + mywrite!(w, "p"); + enc_projection_predicate(w, cx, data) + } + ty::Predicate::WellFormed(data) => { + mywrite!(w, "w"); + enc_ty(w, cx, data); + } + ty::Predicate::ObjectSafe(trait_def_id) => { + mywrite!(w, "O{}|", (cx.ds)(trait_def_id)); + } + } +} + +fn enc_projection_predicate<'a, 'tcx>(w: &mut Encoder, + cx: &ctxt<'a, 'tcx>, + data: &ty::ProjectionPredicate<'tcx>) { + enc_trait_ref(w, cx, data.projection_ty.trait_ref); + mywrite!(w, "{}|", data.projection_ty.item_name); + enc_ty(w, cx, data.ty); +} diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 33d63d833c7..5dedef7ab6c 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -71,6 +71,7 @@ extern crate rustc; extern crate rustc_front; +extern crate rustc_metadata; pub use self::registry::Registry; diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index d121a306c61..51eec07505a 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -11,8 +11,8 @@ //! Used by `rustc` when loading a plugin. use rustc::session::Session; -use rustc::metadata::creader::CrateReader; -use rustc::metadata::cstore::CStore; +use rustc_metadata::creader::CrateReader; +use rustc_metadata::cstore::CStore; use registry::Registry; use std::borrow::ToOwned; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 752e7e55f55..13f7e318163 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -28,7 +28,7 @@ use {resolve_error, ResolutionError}; use self::DuplicateCheckingMode::*; -use rustc::metadata::util::{CrateStore, ChildItem, DlDef, DlField, DlImpl}; +use rustc::middle::cstore::{CrateStore, ChildItem, DlDef, DlField, DlImpl}; use rustc::middle::def::*; use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId}; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6bfe9cd393e..ef03ac520df 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -54,7 +54,7 @@ use self::FallbackChecks::*; use rustc::front::map as hir_map; use rustc::session::Session; use rustc::lint; -use rustc::metadata::util::{CrateStore, DefLike, DlDef}; +use rustc::middle::cstore::{CrateStore, DefLike, DlDef}; use rustc::middle::def::*; use rustc::middle::def_id::DefId; use rustc::middle::pat_util::pat_bindings_hygienic; diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index d7f9002a4f4..f5431554a75 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -21,7 +21,7 @@ use std::process::{Command, Output, Stdio}; use std::ptr; use std::str; -use metadata::util::CrateStore; +use middle::cstore::CrateStore; use libc; use llvm::archive_ro::{ArchiveRO, Child}; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index cefe04f5e35..d7b4243afee 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -17,12 +17,11 @@ use super::svh::Svh; use session::config; use session::config::NoDebugInfo; use session::config::{OutputFilenames, Input, OutputType}; +use session::filesearch; use session::search_paths::PathKind; use session::Session; -use metadata::{util as mdutil}; -use metadata::filesearch; -use metadata::util::{CrateStore, LinkMeta}; -use metadata::util::{LinkagePreference, NativeLibraryKind}; +use middle::cstore::{self, CrateStore, LinkMeta}; +use middle::cstore::{LinkagePreference, NativeLibraryKind}; use middle::dependency_format::Linkage; use middle::ty::{self, Ty}; use rustc::front::map::DefPath; @@ -138,7 +137,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String { let validate = |s: String, span: Option| { - mdutil::validate_crate_name(sess, &s[..], span); + cstore::validate_crate_name(sess, &s[..], span); s }; diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 8235df581c8..1ee1c9f1912 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -16,7 +16,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use back::archive; -use metadata::util::CrateStore; +use middle::cstore::CrateStore; use middle::dependency_format::Linkage; use session::Session; use session::config::CrateTypeDylib; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 67a7f3efb27..b672c49bdca 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -62,7 +62,6 @@ extern crate serialize; #[macro_use] extern crate syntax; pub use rustc::session; -pub use rustc::metadata; pub use rustc::middle; pub use rustc::lint; pub use rustc::util; diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index 34eb1d28263..a95a4c052fa 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -13,7 +13,7 @@ pub use self::Row::*; use super::escape; use super::span_utils::SpanUtils; -use metadata::cstore::LOCAL_CRATE; +use middle::cstore::LOCAL_CRATE; use middle::def_id::{CRATE_DEF_INDEX, DefId}; use middle::ty; diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 30ec1e662b0..d6b33672df0 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -35,6 +35,7 @@ use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use middle::cfg; +use middle::cstore::CrateStore; use middle::def_id::DefId; use middle::infer; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; @@ -42,7 +43,6 @@ use middle::weak_lang_items; use middle::pat_util::simple_name; use middle::subst::Substs; use middle::ty::{self, Ty, HasTypeFlags}; -use metadata::util::CrateStore; use rustc::front::map as hir_map; use rustc_mir::mir_map::MirMap; use session::config::{self, NoDebugInfo, FullDebugInfo}; diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index a52c7f94c3a..0c0bda45d8c 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -22,7 +22,7 @@ use arena::TypedArena; use back::link; use session; use llvm::{self, ValueRef, get_params}; -use metadata::cstore::LOCAL_CRATE; +use middle::cstore::LOCAL_CRATE; use middle::def; use middle::def_id::DefId; use middle::infer; diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 91f17a50e2c..6f40283064b 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -13,8 +13,8 @@ use back::abi; use llvm; use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}; use llvm::{InternalLinkage, ValueRef, Bool, True}; -use metadata::cstore::LOCAL_CRATE; use middle::{check_const, def}; +use middle::cstore::LOCAL_CRATE; use middle::const_eval::{self, ConstVal, ConstEvalErr}; use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg}; use middle::const_eval::{const_int_checked_add, const_uint_checked_add}; diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 1f1d43feeb3..c6ca2e176aa 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -10,7 +10,7 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef}; -use metadata::common::LinkMeta; +use middle::cstore::LinkMeta; use middle::def::ExportMap; use middle::def_id::DefId; use middle::traits; diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 5be4892484b..29965755eac 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::{AvailableExternallyLinkage, InternalLinkage, SetLinkage}; -use metadata::util::{CrateStore, FoundAst, InlinedItem}; +use middle::cstore::{CrateStore, FoundAst, InlinedItem}; use middle::def_id::DefId; use middle::subst::Substs; use trans::base::{push_ctxt, trans_item, get_item_val, trans_fn}; diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index fa37b005539..b102e96af20 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::{ContextRef, ModuleRef}; -use metadata::common::LinkMeta; +use middle::cstore::LinkMeta; pub use self::base::trans_crate; pub use self::context::CrateContext; diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 988d5537e5d..6a23be682e9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -25,7 +25,7 @@ use super::UnresolvedTypeAction; use super::write_call; use CrateCtxt; -use metadata::cstore::LOCAL_CRATE; +use middle::cstore::LOCAL_CRATE; use middle::def_id::DefId; use middle::infer; use middle::ty::{self, LvaluePreference, Ty}; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f4f4dc90feb..955bc92a8f3 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -17,12 +17,12 @@ use astconv::AstConv; use check::{self, FnCtxt}; use front::map as hir_map; use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, HasTypeFlags}; +use middle::cstore::{self, CrateStore, DefLike}; use middle::def; use middle::def_id::DefId; use middle::lang_items::FnOnceTraitLangItem; use middle::subst::Substs; use middle::traits::{Obligation, SelectionContext}; -use metadata::util::{self as mdutil, CrateStore, DefLike}; use util::nodemap::{FnvHashSet}; use syntax::ast; @@ -418,13 +418,13 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { fn handle_external_def(traits: &mut AllTraitsVec, external_mods: &mut FnvHashSet, ccx: &CrateCtxt, - cstore: &for<'a> mdutil::CrateStore<'a>, - dl: mdutil::DefLike) { + cstore: &for<'a> cstore::CrateStore<'a>, + dl: cstore::DefLike) { match dl { - mdutil::DlDef(def::DefTrait(did)) => { + cstore::DlDef(def::DefTrait(did)) => { traits.push(TraitInfo::new(did)); } - mdutil::DlDef(def::DefMod(did)) => { + cstore::DlDef(def::DefMod(did)) => { if !external_mods.insert(did) { return; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c375eb19a37..be60d2f3dcf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -83,8 +83,8 @@ use self::TupleArgumentsFlag::*; use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode}; use check::_match::pat_ctxt; use fmt_macros::{Parser, Piece, Position}; -use metadata::cstore::LOCAL_CRATE; use middle::astconv_util::prohibit_type_params; +use middle::cstore::LOCAL_CRATE; use middle::def; use middle::def_id::DefId; use middle::infer; diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 8eeafb9b432..e6e31ba0819 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -11,7 +11,7 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use metadata::cstore::LOCAL_CRATE; +use middle::cstore::LOCAL_CRATE; use middle::def_id::DefId; use middle::traits; use middle::ty; diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 6a50ceba2f0..693c8716ab5 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -11,8 +11,7 @@ //! Overlap: No two impls for the same trait are implemented for the //! same type. -use metadata::cstore::LOCAL_CRATE; -use metadata::util::CrateStore; +use middle::cstore::{CrateStore, LOCAL_CRATE}; use middle::def_id::DefId; use middle::traits; use middle::ty; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 3d28a912179..4c09df41895 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -99,7 +99,6 @@ extern crate rustc_back; pub use rustc::front; pub use rustc::lint; -pub use rustc::metadata; pub use rustc::middle; pub use rustc::session; pub use rustc::util; -- cgit 1.4.1-3-g733a5