rust/src/librustc_metadata/encoder.rs

1908 lines
69 KiB
Rust

// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Metadata encoding
#![allow(unused_must_use)] // everything is just a MemWriter, can't fail
#![allow(non_camel_case_types)]
use astencode::encode_inlined_item;
use common::*;
use cstore;
use decoder;
use def_key;
use index::{self, IndexData};
use middle::cstore::{InlinedItemRef, LinkMeta};
use rustc::hir::def;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
use middle::dependency_format::Linkage;
use rustc::dep_graph::DepNode;
use rustc::traits::specialization_graph;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::hir::svh::Svh;
use rustc::mir::mir_map::MirMap;
use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro};
use rustc::util::nodemap::{FnvHashMap, NodeSet};
use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque};
use rustc_serialize as serialize;
use std::cell::RefCell;
use std::intrinsics;
use std::io::prelude::*;
use std::io::Cursor;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::u32;
use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID};
use syntax::attr;
use syntax;
use syntax_pos::BytePos;
use rbml;
use rustc::hir::{self, PatKind};
use rustc::hir::intravisit::Visitor;
use rustc::hir::intravisit;
use rustc::hir::map::DefKey;
use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, Untracked, XRef};
pub struct EncodeContext<'a, 'tcx: 'a> {
rbml_w: rbml::writer::Encoder<'a>,
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
reexports: &'a def::ExportMap,
link_meta: &'a LinkMeta,
cstore: &'a cstore::CStore,
type_shorthands: RefCell<FnvHashMap<Ty<'tcx>, usize>>,
reachable: &'a NodeSet,
mir_map: &'a MirMap<'tcx>,
}
impl<'a, 'tcx> Deref for EncodeContext<'a, 'tcx> {
type Target = rbml::writer::Encoder<'a>;
fn deref(&self) -> &Self::Target {
&self.rbml_w
}
}
impl<'a, 'tcx> DerefMut for EncodeContext<'a, 'tcx> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.rbml_w
}
}
macro_rules! encoder_methods {
($($name:ident($ty:ty);)*) => {
$(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
self.opaque.$name(value)
})*
}
}
impl<'a, 'tcx> serialize::Encoder for ::encoder::EncodeContext<'a, 'tcx> {
type Error = <opaque::Encoder<'a> as serialize::Encoder>::Error;
fn emit_nil(&mut self) -> Result<(), Self::Error> {
Ok(())
}
encoder_methods! {
emit_usize(usize);
emit_u64(u64);
emit_u32(u32);
emit_u16(u16);
emit_u8(u8);
emit_isize(isize);
emit_i64(i64);
emit_i32(i32);
emit_i16(i16);
emit_i8(i8);
emit_bool(bool);
emit_f64(f64);
emit_f32(f32);
emit_char(char);
emit_str(&str);
}
}
impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
let existing_shorthand = self.type_shorthands.borrow().get(ty).cloned();
if let Some(shorthand) = existing_shorthand {
return self.emit_usize(shorthand);
}
let start = self.mark_stable_position();
ty.sty.encode(self)?;
let len = self.mark_stable_position() - start;
// The shorthand encoding uses the same usize as the
// discriminant, with an offset so they can't conflict.
let discriminant = unsafe { intrinsics::discriminant_value(&ty.sty) };
assert!(discriminant < TYPE_SHORTHAND_OFFSET as u64);
let shorthand = start + TYPE_SHORTHAND_OFFSET;
// Get the number of bits that leb128 could fit
// in the same space as the fully encoded type.
let leb128_bits = len * 7;
// Check that the shorthand is a not longer than the
// full encoding itself, i.e. it's an obvious win.
if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) {
self.type_shorthands.borrow_mut().insert(*ty, shorthand);
}
Ok(())
}
}
fn encode_name(ecx: &mut EncodeContext, name: Name) {
ecx.wr_tagged_str(tag_paths_data_name, &name.as_str());
}
fn encode_def_id(ecx: &mut EncodeContext, id: DefId) {
ecx.wr_tagged_u64(tag_def_id, def_to_u64(id));
}
fn encode_def_key(ecx: &mut EncodeContext, key: DefKey) {
let simple_key = def_key::simplify_def_key(key);
ecx.start_tag(tag_def_key);
simple_key.encode(ecx);
ecx.end_tag();
}
/// 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: &mut EncodeContext, def_id: DefId) {
encode_def_id(ecx, def_id);
let def_key = ecx.tcx.map.def_key(def_id);
encode_def_key(ecx, def_key);
}
fn encode_trait_ref<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>,
trait_ref: ty::TraitRef<'tcx>,
tag: usize) {
ecx.start_tag(tag);
trait_ref.encode(ecx).unwrap();
ecx.end_tag();
}
// Item info table encoding
fn encode_family(ecx: &mut EncodeContext, c: char) {
ecx.wr_tagged_u8(tag_items_data_item_family, c as u8);
}
pub fn def_to_u64(did: DefId) -> u64 {
(did.krate.as_u32() as u64) << 32 | (did.index.as_u32() as u64)
}
pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String {
format!("{}:{}", did.krate, did.index.as_usize())
}
fn encode_item_variances(ecx: &mut EncodeContext, id: NodeId) {
let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id));
ecx.start_tag(tag_item_variances);
v.encode(ecx);
ecx.end_tag();
}
impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> {
fn encode_bounds_and_type_for_item(&mut self, def_id: DefId) {
let tcx = self.tcx;
self.encode_bounds_and_type(&tcx.lookup_item_type(def_id),
&tcx.lookup_predicates(def_id));
}
fn encode_bounds_and_type(&mut self,
scheme: &ty::TypeScheme<'tcx>,
predicates: &ty::GenericPredicates<'tcx>) {
self.encode_generics(&scheme.generics, &predicates);
self.encode_type(scheme.ty);
}
}
fn encode_variant_id(ecx: &mut EncodeContext, vid: DefId) {
let id = def_to_u64(vid);
ecx.wr_tagged_u64(tag_items_data_item_variant, id);
ecx.wr_tagged_u64(tag_mod_child, id);
}
impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> {
fn encode_type(&mut self, typ: Ty<'tcx>) {
self.start_tag(tag_items_data_item_type);
typ.encode(self.ecx).unwrap();
self.end_tag();
}
fn encode_disr_val(&mut self,
disr_val: ty::Disr) {
// convert to u64 so just the number is printed, without any type info
self.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
}
fn encode_parent_item(&mut self, id: DefId) {
self.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id));
}
fn encode_struct_fields(&mut self,
variant: ty::VariantDef) {
for f in &variant.fields {
if variant.kind == ty::VariantKind::Tuple {
self.start_tag(tag_item_unnamed_field);
} else {
self.start_tag(tag_item_field);
encode_name(self, f.name);
}
self.encode_struct_field_family(f.vis);
encode_def_id(self, f.did);
self.end_tag();
}
}
}
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
fn encode_enum_variant_infos(&mut self, enum_did: DefId) {
debug!("encode_enum_variant_info(enum_did={:?})", enum_did);
let def = self.tcx.lookup_adt_def(enum_did);
self.encode_fields(enum_did);
for (i, variant) in def.variants.iter().enumerate() {
self.record(variant.did,
ItemContentBuilder::encode_enum_variant_info,
(enum_did, Untracked(i)));
}
}
}
impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> {
/// Encode data for the given variant of the given ADT. The
/// index of the variant is untracked: this is ok because we
/// will have to lookup the adt-def by its id, and that gives us
/// the right to access any information in the adt-def (including,
/// e.g., the length of the various vectors).
fn encode_enum_variant_info(&mut self,
(enum_did, Untracked(index)):
(DefId, Untracked<usize>)) {
let tcx = self.tcx;
let def = tcx.lookup_adt_def(enum_did);
let variant = &def.variants[index];
let vid = variant.did;
encode_def_id_and_key(self, vid);
encode_family(self, match variant.kind {
ty::VariantKind::Struct => 'V',
ty::VariantKind::Tuple => 'v',
ty::VariantKind::Unit => 'w',
});
encode_name(self, variant.name);
self.encode_parent_item(enum_did);
let enum_id = tcx.map.as_local_node_id(enum_did).unwrap();
let enum_vis = &tcx.map.expect_item(enum_id).vis;
self.encode_visibility(enum_vis);
let attrs = tcx.get_attrs(vid);
encode_attributes(self, &attrs);
self.encode_repr_attrs(&attrs);
let stab = tcx.lookup_stability(vid);
let depr = tcx.lookup_deprecation(vid);
encode_stability(self, stab);
encode_deprecation(self, depr);
self.encode_struct_fields(variant);
self.encode_disr_val(variant.disr_val);
self.encode_bounds_and_type_for_item(vid);
}
}
fn encode_reexports(ecx: &mut EncodeContext, 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);
ecx.start_tag(tag_items_data_item_reexport);
ecx.wr_tagged_u64(tag_items_data_item_reexport_def_id,
def_to_u64(exp.def_id));
ecx.wr_tagged_str(tag_items_data_item_reexport_name,
&exp.name.as_str());
ecx.end_tag();
}
},
None => debug!("(encoding info for module) found no reexports for {}", id),
}
}
impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> {
fn encode_info_for_mod(&mut self,
FromId(id, (md, attrs, name, vis)):
FromId<(&hir::Mod, &[ast::Attribute], Name, &hir::Visibility)>) {
let tcx = self.tcx;
encode_def_id_and_key(self, tcx.map.local_def_id(id));
encode_family(self, 'm');
encode_name(self, 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 {
self.wr_tagged_u64(tag_mod_child,
def_to_u64(tcx.map.local_def_id(item_id.id)));
}
self.encode_visibility(vis);
let stab = tcx.lookup_stability(tcx.map.local_def_id(id));
let depr = tcx.lookup_deprecation(tcx.map.local_def_id(id));
encode_stability(self, stab);
encode_deprecation(self, depr);
// 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(self, id);
}
encode_attributes(self, attrs);
}
fn encode_struct_field_family(&mut self,
visibility: ty::Visibility) {
encode_family(self, if visibility.is_public() { 'g' } else { 'N' });
}
fn encode_visibility<T: HasVisibility>(&mut self, visibility: T) {
let ch = if visibility.is_public() { 'y' } else { 'i' };
self.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
}
}
trait HasVisibility: Sized {
fn is_public(self) -> bool;
}
impl<'a> HasVisibility for &'a hir::Visibility {
fn is_public(self) -> bool {
*self == hir::Public
}
}
impl HasVisibility for ty::Visibility {
fn is_public(self) -> bool {
self == ty::Visibility::Public
}
}
fn encode_constness(ecx: &mut EncodeContext, constness: hir::Constness) {
ecx.start_tag(tag_items_data_item_constness);
let ch = match constness {
hir::Constness::Const => 'c',
hir::Constness::NotConst => 'n',
};
ecx.wr_str(&ch.to_string());
ecx.end_tag();
}
fn encode_defaultness(ecx: &mut EncodeContext, defaultness: hir::Defaultness) {
let ch = match defaultness {
hir::Defaultness::Default => 'd',
hir::Defaultness::Final => 'f',
};
ecx.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8);
}
fn encode_explicit_self(ecx: &mut EncodeContext,
explicit_self: &ty::ExplicitSelfCategory) {
let tag = tag_item_trait_method_explicit_self;
// Encode the base self type.
match *explicit_self {
ty::ExplicitSelfCategory::Static => {
ecx.wr_tagged_bytes(tag, &['s' as u8]);
}
ty::ExplicitSelfCategory::ByValue => {
ecx.wr_tagged_bytes(tag, &['v' as u8]);
}
ty::ExplicitSelfCategory::ByBox => {
ecx.wr_tagged_bytes(tag, &['~' as u8]);
}
ty::ExplicitSelfCategory::ByReference(_, m) => {
// FIXME(#4846) encode custom lifetime
let ch = encode_mutability(m);
ecx.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(ecx: &mut EncodeContext, sort: char) {
ecx.wr_tagged_u8(tag_item_trait_item_sort, sort as u8);
}
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
fn encode_fields(&mut self,
adt_def_id: DefId) {
let def = self.tcx.lookup_adt_def(adt_def_id);
for (variant_index, variant) in def.variants.iter().enumerate() {
for (field_index, field) in variant.fields.iter().enumerate() {
self.record(field.did,
ItemContentBuilder::encode_field,
(adt_def_id, Untracked((variant_index, field_index))));
}
}
}
}
impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> {
/// Encode data for the given field of the given variant of the
/// given ADT. The indices of the variant/field are untracked:
/// this is ok because we will have to lookup the adt-def by its
/// id, and that gives us the right to access any information in
/// the adt-def (including, e.g., the length of the various
/// vectors).
fn encode_field(&mut self,
(adt_def_id, Untracked((variant_index, field_index))):
(DefId, Untracked<(usize, usize)>)) {
let tcx = self.tcx;
let def = tcx.lookup_adt_def(adt_def_id);
let variant = &def.variants[variant_index];
let field = &variant.fields[field_index];
let nm = field.name;
debug!("encode_field: encoding {} {:?}", nm, field.did);
self.encode_struct_field_family(field.vis);
encode_name(self, nm);
self.encode_bounds_and_type_for_item(field.did);
encode_def_id_and_key(self, field.did);
let stab = tcx.lookup_stability(field.did);
let depr = tcx.lookup_deprecation(field.did);
encode_stability(self, stab);
encode_deprecation(self, depr);
}
fn encode_struct_ctor(&mut self,
(struct_def_id, struct_node_id, ctor_node_id):
(DefId, ast::NodeId, ast::NodeId)) {
let tcx = self.tcx;
let def = tcx.lookup_adt_def(struct_def_id);
let variant = def.struct_variant();
let item = tcx.map.expect_item(struct_node_id);
let ctor_def_id = tcx.map.local_def_id(ctor_node_id);
encode_def_id_and_key(self, ctor_def_id);
encode_family(self, match variant.kind {
ty::VariantKind::Struct => 'S',
ty::VariantKind::Tuple => 's',
ty::VariantKind::Unit => 'u',
});
self.encode_bounds_and_type_for_item(ctor_def_id);
encode_name(self, item.name);
self.encode_parent_item(struct_def_id);
let stab = tcx.lookup_stability(ctor_def_id);
let depr = tcx.lookup_deprecation(ctor_def_id);
encode_stability(self, stab);
encode_deprecation(self, depr);
// 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
self.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]);
}
fn encode_generics(&mut self,
generics: &ty::Generics<'tcx>,
predicates: &ty::GenericPredicates<'tcx>)
{
self.start_tag(tag_item_generics);
generics.encode(self.ecx).unwrap();
self.end_tag();
self.encode_predicates(predicates, tag_item_predicates);
}
fn encode_predicates(&mut self,
predicates: &ty::GenericPredicates<'tcx>,
tag: usize) {
self.start_tag(tag);
if let Some(def_id) = predicates.parent {
self.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id));
}
for predicate in &predicates.predicates {
let xref = self.add_xref(XRef::Predicate(predicate.clone()));
self.wr_tagged_u32(tag_predicate, xref);
}
self.end_tag();
}
fn encode_method_ty_fields(&mut self, method_ty: &ty::Method<'tcx>) {
encode_def_id_and_key(self, method_ty.def_id);
encode_name(self, method_ty.name);
self.encode_generics(&method_ty.generics, &method_ty.predicates);
self.encode_visibility(method_ty.vis);
encode_explicit_self(self, &method_ty.explicit_self);
match method_ty.explicit_self {
ty::ExplicitSelfCategory::Static => {
encode_family(self, STATIC_METHOD_FAMILY);
}
_ => encode_family(self, METHOD_FAMILY)
}
}
fn encode_info_for_trait_item(&mut self,
(trait_def_id, item_def_id, trait_item):
(DefId, DefId, &hir::TraitItem)) {
let tcx = self.tcx;
self.encode_parent_item(trait_def_id);
let stab = tcx.lookup_stability(item_def_id);
let depr = tcx.lookup_deprecation(item_def_id);
encode_stability(self, stab);
encode_deprecation(self, depr);
let trait_item_type =
tcx.impl_or_trait_item(item_def_id);
let is_nonstatic_method;
match trait_item_type {
ty::ConstTraitItem(associated_const) => {
encode_name(self, associated_const.name);
encode_def_id_and_key(self, associated_const.def_id);
self.encode_visibility(associated_const.vis);
encode_family(self, 'C');
self.encode_bounds_and_type_for_item(associated_const.def_id);
is_nonstatic_method = false;
}
ty::MethodTraitItem(method_ty) => {
let method_def_id = item_def_id;
self.encode_method_ty_fields(&method_ty);
match method_ty.explicit_self {
ty::ExplicitSelfCategory::Static => {
encode_family(self, STATIC_METHOD_FAMILY);
}
_ => {
encode_family(self, METHOD_FAMILY);
}
}
self.encode_bounds_and_type_for_item(method_def_id);
is_nonstatic_method = method_ty.explicit_self !=
ty::ExplicitSelfCategory::Static;
}
ty::TypeTraitItem(associated_type) => {
encode_name(self, associated_type.name);
encode_def_id_and_key(self, associated_type.def_id);
encode_item_sort(self, 't');
encode_family(self, 'y');
if let Some(ty) = associated_type.ty {
self.encode_type(ty);
}
is_nonstatic_method = false;
}
}
encode_attributes(self, &trait_item.attrs);
match trait_item.node {
hir::ConstTraitItem(_, ref default) => {
if default.is_some() {
encode_item_sort(self, 'C');
} else {
encode_item_sort(self, 'c');
}
encode_inlined_item(self,
InlinedItemRef::TraitItem(trait_def_id, trait_item));
self.encode_mir(item_def_id);
}
hir::MethodTraitItem(ref sig, ref body) => {
// If this is a static method, we've already
// encoded self.
if is_nonstatic_method {
self.encode_bounds_and_type_for_item(item_def_id);
}
if body.is_some() {
encode_item_sort(self, 'p');
self.encode_mir(item_def_id);
} else {
encode_item_sort(self, 'r');
}
self.encode_method_argument_names(&sig.decl);
}
hir::TypeTraitItem(..) => {}
}
}
fn encode_info_for_impl_item(&mut self,
(impl_id, impl_item_def_id, ast_item):
(NodeId, DefId, Option<&hir::ImplItem>)) {
match self.tcx.impl_or_trait_item(impl_item_def_id) {
ty::ConstTraitItem(ref associated_const) => {
self.encode_info_for_associated_const(&associated_const,
impl_id,
ast_item)
}
ty::MethodTraitItem(ref method_type) => {
self.encode_info_for_method(&method_type,
false,
impl_id,
ast_item)
}
ty::TypeTraitItem(ref associated_type) => {
self.encode_info_for_associated_type(&associated_type,
impl_id,
ast_item)
}
}
}
fn encode_info_for_associated_const(&mut self,
associated_const: &ty::AssociatedConst,
parent_id: NodeId,
impl_item_opt: Option<&hir::ImplItem>) {
let tcx = self.tcx;
debug!("encode_info_for_associated_const({:?},{:?})",
associated_const.def_id,
associated_const.name);
encode_def_id_and_key(self, associated_const.def_id);
encode_name(self, associated_const.name);
self.encode_visibility(associated_const.vis);
encode_family(self, 'C');
self.encode_parent_item(tcx.map.local_def_id(parent_id));
encode_item_sort(self, 'C');
self.encode_bounds_and_type_for_item(associated_const.def_id);
let stab = tcx.lookup_stability(associated_const.def_id);
let depr = tcx.lookup_deprecation(associated_const.def_id);
encode_stability(self, stab);
encode_deprecation(self, depr);
if let Some(ii) = impl_item_opt {
encode_attributes(self, &ii.attrs);
encode_defaultness(self, ii.defaultness);
encode_inlined_item(self,
InlinedItemRef::ImplItem(tcx.map.local_def_id(parent_id),
ii));
self.encode_mir(associated_const.def_id);
}
}
fn encode_info_for_method(&mut self,
m: &ty::Method<'tcx>,
is_default_impl: bool,
parent_id: NodeId,
impl_item_opt: Option<&hir::ImplItem>) {
let tcx = self.tcx;
debug!("encode_info_for_method: {:?} {:?}", m.def_id,
m.name);
self.encode_method_ty_fields(m);
self.encode_parent_item(tcx.map.local_def_id(parent_id));
encode_item_sort(self, 'r');
let stab = tcx.lookup_stability(m.def_id);
let depr = tcx.lookup_deprecation(m.def_id);
encode_stability(self, stab);
encode_deprecation(self, depr);
self.encode_bounds_and_type_for_item(m.def_id);
if let Some(impl_item) = impl_item_opt {
if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
encode_attributes(self, &impl_item.attrs);
let generics = tcx.lookup_generics(m.def_id);
let types = generics.parent_types as usize + generics.types.len();
let needs_inline = types > 0 || is_default_impl ||
attr::requests_inline(&impl_item.attrs);
if sig.constness == hir::Constness::Const {
encode_inlined_item(
self,
InlinedItemRef::ImplItem(tcx.map.local_def_id(parent_id),
impl_item));
}
if needs_inline || sig.constness == hir::Constness::Const {
self.encode_mir(m.def_id);
}
encode_constness(self, sig.constness);
encode_defaultness(self, impl_item.defaultness);
self.encode_method_argument_names(&sig.decl);
}
}
}
fn encode_info_for_associated_type(&mut self,
associated_type: &ty::AssociatedType<'tcx>,
parent_id: NodeId,
impl_item_opt: Option<&hir::ImplItem>) {
let tcx = self.tcx;
debug!("encode_info_for_associated_type({:?},{:?})",
associated_type.def_id,
associated_type.name);
encode_def_id_and_key(self, associated_type.def_id);
encode_name(self, associated_type.name);
self.encode_visibility(associated_type.vis);
encode_family(self, 'y');
self.encode_parent_item(tcx.map.local_def_id(parent_id));
encode_item_sort(self, 't');
let stab = tcx.lookup_stability(associated_type.def_id);
let depr = tcx.lookup_deprecation(associated_type.def_id);
encode_stability(self, stab);
encode_deprecation(self, depr);
if let Some(ii) = impl_item_opt {
encode_attributes(self, &ii.attrs);
encode_defaultness(self, ii.defaultness);
}
if let Some(ty) = associated_type.ty {
self.encode_type(ty);
}
}
fn encode_method_argument_names(&mut self,
decl: &hir::FnDecl) {
self.start_tag(tag_method_argument_names);
for arg in &decl.inputs {
let tag = tag_method_argument_name;
if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
let name = path1.node.as_str();
self.wr_tagged_bytes(tag, name.as_bytes());
} else {
self.wr_tagged_bytes(tag, &[]);
}
}
self.end_tag();
}
fn encode_repr_attrs(&mut self,
attrs: &[ast::Attribute]) {
let mut repr_attrs = Vec::new();
for attr in attrs {
repr_attrs.extend(attr::find_repr_attrs(self.tcx.sess.diagnostic(),
attr));
}
self.start_tag(tag_items_data_item_repr);
repr_attrs.encode(self.ecx);
self.end_tag();
}
fn encode_mir(&mut self, def_id: DefId) {
if let Some(mir) = self.mir_map.map.get(&def_id) {
self.start_tag(tag_mir as usize);
mir.encode(self.ecx);
self.end_tag();
}
}
}
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: &mut EncodeContext,
def_id: DefId) {
match ecx.tcx.inherent_impls.borrow().get(&def_id) {
None => {}
Some(implementations) => {
for &impl_def_id in implementations.iter() {
ecx.start_tag(tag_items_data_item_inherent_impl);
encode_def_id(ecx, impl_def_id);
ecx.end_tag();
}
}
}
}
fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) {
stab_opt.map(|stab| {
ecx.start_tag(tag_items_data_item_stability);
stab.encode(ecx).unwrap();
ecx.end_tag();
});
}
fn encode_deprecation(ecx: &mut EncodeContext, depr_opt: Option<attr::Deprecation>) {
depr_opt.map(|depr| {
ecx.start_tag(tag_items_data_item_deprecation);
depr.encode(ecx).unwrap();
ecx.end_tag();
});
}
fn encode_parent_impl(ecx: &mut EncodeContext, parent_opt: Option<DefId>) {
parent_opt.map(|parent| {
ecx.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent));
});
}
fn encode_xrefs<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>,
xrefs: FnvHashMap<XRef<'tcx>, u32>)
{
let mut xref_positions = vec![0; xrefs.len()];
// Encode XRefs sorted by their ID
let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect();
sorted_xrefs.sort_by_key(|&(_, id)| id);
ecx.start_tag(tag_xref_data);
for (xref, id) in sorted_xrefs.into_iter() {
xref_positions[id as usize] = ecx.mark_stable_position() as u32;
match xref {
XRef::Predicate(p) => p.encode(ecx).unwrap()
}
}
ecx.mark_stable_position();
ecx.end_tag();
ecx.start_tag(tag_xref_index);
index::write_dense_index(xref_positions, &mut ecx.opaque.cursor);
ecx.end_tag();
}
impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> {
fn encode_info_for_item(&mut self,
(def_id, item): (DefId, &hir::Item)) {
let tcx = self.tcx;
debug!("encoding info for item at {}",
tcx.sess.codemap().span_to_string(item.span));
let vis = &item.vis;
let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || {
(tcx.lookup_stability(tcx.map.local_def_id(item.id)),
tcx.lookup_deprecation(tcx.map.local_def_id(item.id)))
});
match item.node {
hir::ItemStatic(_, m, _) => {
encode_def_id_and_key(self, def_id);
if m == hir::MutMutable {
encode_family(self, 'b');
} else {
encode_family(self, 'c');
}
self.encode_bounds_and_type_for_item(def_id);
encode_name(self, item.name);
self.encode_visibility(vis);
encode_stability(self, stab);
encode_deprecation(self, depr);
encode_attributes(self, &item.attrs);
}
hir::ItemConst(..) => {
encode_def_id_and_key(self, def_id);
encode_family(self, 'C');
self.encode_bounds_and_type_for_item(def_id);
encode_name(self, item.name);
encode_attributes(self, &item.attrs);
encode_inlined_item(self, InlinedItemRef::Item(def_id, item));
self.encode_mir(def_id);
self.encode_visibility(vis);
encode_stability(self, stab);
encode_deprecation(self, depr);
}
hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
encode_def_id_and_key(self, def_id);
encode_family(self, FN_FAMILY);
let tps_len = generics.ty_params.len();
self.encode_bounds_and_type_for_item(def_id);
encode_name(self, item.name);
encode_attributes(self, &item.attrs);
let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
if constness == hir::Constness::Const {
encode_inlined_item(self, InlinedItemRef::Item(def_id, item));
}
if needs_inline || constness == hir::Constness::Const {
self.encode_mir(def_id);
}
encode_constness(self, constness);
self.encode_visibility(vis);
encode_stability(self, stab);
encode_deprecation(self, depr);
self.encode_method_argument_names(&decl);
}
hir::ItemMod(ref m) => {
self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, item.name, &item.vis)));
}
hir::ItemForeignMod(ref fm) => {
encode_def_id_and_key(self, def_id);
encode_family(self, 'n');
encode_name(self, item.name);
// Encode all the items in self module.
for foreign_item in &fm.items {
self.wr_tagged_u64(
tag_mod_child,
def_to_u64(tcx.map.local_def_id(foreign_item.id)));
}
self.encode_visibility(vis);
encode_stability(self, stab);
encode_deprecation(self, depr);
}
hir::ItemTy(..) => {
encode_def_id_and_key(self, def_id);
encode_family(self, 'y');
self.encode_bounds_and_type_for_item(def_id);
encode_name(self, item.name);
self.encode_visibility(vis);
encode_stability(self, stab);
encode_deprecation(self, depr);
}
hir::ItemEnum(ref enum_definition, _) => {
encode_def_id_and_key(self, def_id);
encode_family(self, 't');
encode_item_variances(self, item.id);
self.encode_bounds_and_type_for_item(def_id);
encode_name(self, item.name);
encode_attributes(self, &item.attrs);
self.encode_repr_attrs(&item.attrs);
for v in &enum_definition.variants {
encode_variant_id(self, tcx.map.local_def_id(v.node.data.id()));
}
// Encode inherent implementations for self enumeration.
encode_inherent_implementations(self, def_id);
self.encode_visibility(vis);
encode_stability(self, stab);
encode_deprecation(self, depr);
}
hir::ItemStruct(ref struct_def, _) => {
/* Index the class*/
let def = tcx.lookup_adt_def(def_id);
let variant = def.struct_variant();
/* Now, make an item for the class itself */
encode_def_id_and_key(self, def_id);
encode_family(self, match *struct_def {
hir::VariantData::Struct(..) => 'S',
hir::VariantData::Tuple(..) => 's',
hir::VariantData::Unit(..) => 'u',
});
self.encode_bounds_and_type_for_item(def_id);
encode_item_variances(self, item.id);
encode_name(self, item.name);
encode_attributes(self, &item.attrs);
encode_stability(self, stab);
encode_deprecation(self, depr);
self.encode_visibility(vis);
self.encode_repr_attrs(&item.attrs);
/* Encode def_ids for each field and method
for methods, write all the stuff get_trait_method
needs to know*/
self.encode_struct_fields(variant);
// Encode inherent implementations for self structure.
encode_inherent_implementations(self, def_id);
if !struct_def.is_struct() {
let ctor_did = tcx.map.local_def_id(struct_def.id());
self.wr_tagged_u64(tag_items_data_item_struct_ctor,
def_to_u64(ctor_did));
}
}
hir::ItemUnion(..) => {
let def = self.tcx.lookup_adt_def(def_id);
let variant = def.struct_variant();
encode_def_id_and_key(self, def_id);
encode_family(self, 'U');
self.encode_bounds_and_type_for_item(def_id);
encode_item_variances(self, item.id);
encode_name(self, item.name);
encode_attributes(self, &item.attrs);
encode_stability(self, stab);
encode_deprecation(self, depr);
self.encode_visibility(vis);
self.encode_repr_attrs(&item.attrs);
/* Encode def_ids for each field and method
for methods, write all the stuff get_trait_method
needs to know*/
self.encode_struct_fields(variant);
encode_inlined_item(self, InlinedItemRef::Item(def_id, item));
self.encode_mir(def_id);
// Encode inherent implementations for self union.
encode_inherent_implementations(self, def_id);
}
hir::ItemDefaultImpl(unsafety, _) => {
encode_def_id_and_key(self, def_id);
encode_family(self, 'd');
encode_name(self, item.name);
encode_unsafety(self, unsafety);
let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(item.id)).unwrap();
encode_trait_ref(self, trait_ref, tag_item_trait_ref);
}
hir::ItemImpl(unsafety, polarity, ..) => {
// We need to encode information about the default methods we
// have inherited, so we drive self based on the impl structure.
let impl_items = tcx.impl_items.borrow();
let items = &impl_items[&def_id];
encode_def_id_and_key(self, def_id);
encode_family(self, 'i');
self.encode_bounds_and_type_for_item(def_id);
encode_name(self, item.name);
encode_attributes(self, &item.attrs);
encode_unsafety(self, unsafety);
encode_polarity(self, polarity);
match
tcx.custom_coerce_unsized_kinds
.borrow()
.get(&tcx.map.local_def_id(item.id))
{
Some(&kind) => {
self.start_tag(tag_impl_coerce_unsized_kind);
kind.encode(self.ecx);
self.end_tag();
}
None => {}
}
for &item_def_id in items {
self.start_tag(tag_item_impl_item);
match item_def_id {
ty::ConstTraitItemId(item_def_id) => {
encode_def_id(self, item_def_id);
encode_item_sort(self, 'C');
}
ty::MethodTraitItemId(item_def_id) => {
encode_def_id(self, item_def_id);
encode_item_sort(self, 'r');
}
ty::TypeTraitItemId(item_def_id) => {
encode_def_id(self, item_def_id);
encode_item_sort(self, 't');
}
}
self.end_tag();
}
let did = tcx.map.local_def_id(item.id);
if let Some(trait_ref) = tcx.impl_trait_ref(did) {
encode_trait_ref(self, trait_ref, tag_item_trait_ref);
let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
let parent = trait_def.ancestors(did)
.skip(1)
.next()
.and_then(|node| match node {
specialization_graph::Node::Impl(parent) =>
Some(parent),
_ => None,
});
encode_parent_impl(self, parent);
}
encode_stability(self, stab);
encode_deprecation(self, depr);
}
hir::ItemTrait(..) => {
encode_def_id_and_key(self, def_id);
encode_family(self, 'I');
encode_item_variances(self, item.id);
let trait_def = tcx.lookup_trait_def(def_id);
let trait_predicates = tcx.lookup_predicates(def_id);
encode_unsafety(self, trait_def.unsafety);
encode_paren_sugar(self, trait_def.paren_sugar);
encode_defaulted(self, tcx.trait_has_default_impl(def_id));
encode_associated_type_names(self, &trait_def.associated_type_names);
self.encode_generics(&trait_def.generics, &trait_predicates);
self.encode_predicates(&tcx.lookup_super_predicates(def_id),
tag_item_super_predicates);
encode_trait_ref(self, trait_def.trait_ref, tag_item_trait_ref);
encode_name(self, item.name);
encode_attributes(self, &item.attrs);
self.encode_visibility(vis);
encode_stability(self, stab);
encode_deprecation(self, depr);
for &method_def_id in tcx.trait_item_def_ids(def_id).iter() {
self.start_tag(tag_item_trait_item);
match method_def_id {
ty::ConstTraitItemId(const_def_id) => {
encode_def_id(self, const_def_id);
encode_item_sort(self, 'C');
}
ty::MethodTraitItemId(method_def_id) => {
encode_def_id(self, method_def_id);
encode_item_sort(self, 'r');
}
ty::TypeTraitItemId(type_def_id) => {
encode_def_id(self, type_def_id);
encode_item_sort(self, 't');
}
}
self.end_tag();
self.wr_tagged_u64(tag_mod_child,
def_to_u64(method_def_id.def_id()));
}
// Encode inherent implementations for self trait.
encode_inherent_implementations(self, def_id);
}
hir::ItemExternCrate(_) | hir::ItemUse(_) => {
bug!("cannot encode info for item {:?}", item)
}
}
}
}
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
/// In some cases, along with the item itself, we also
/// encode some sub-items. Usually we want some info from the item
/// so it's easier to do that here then to wait until we would encounter
/// normally in the visitor walk.
fn encode_addl_info_for_item(&mut self,
item: &hir::Item) {
let def_id = self.tcx.map.local_def_id(item.id);
match item.node {
hir::ItemStatic(..) |
hir::ItemConst(..) |
hir::ItemFn(..) |
hir::ItemMod(..) |
hir::ItemForeignMod(..) |
hir::ItemExternCrate(..) |
hir::ItemUse(..) |
hir::ItemDefaultImpl(..) |
hir::ItemTy(..) => {
// no sub-item recording needed in these cases
}
hir::ItemEnum(..) => {
self.encode_enum_variant_infos(def_id);
}
hir::ItemStruct(ref struct_def, _) => {
self.encode_addl_struct_info(def_id, struct_def.id(), item);
}
hir::ItemUnion(..) => {
self.encode_addl_union_info(def_id);
}
hir::ItemImpl(.., ref ast_items) => {
self.encode_addl_impl_info(def_id, item.id, ast_items);
}
hir::ItemTrait(.., ref trait_items) => {
self.encode_addl_trait_info(def_id, trait_items);
}
}
}
fn encode_addl_struct_info(&mut self,
def_id: DefId,
struct_node_id: ast::NodeId,
item: &hir::Item) {
let def = self.tcx.lookup_adt_def(def_id);
let variant = def.struct_variant();
self.encode_fields(def_id);
// If this is a tuple-like struct, encode the type of the constructor.
match variant.kind {
ty::VariantKind::Struct => {
// no value for structs like struct Foo { ... }
}
ty::VariantKind::Tuple | ty::VariantKind::Unit => {
// there is a value for structs like `struct
// Foo()` and `struct Foo`
let ctor_def_id = self.tcx.map.local_def_id(struct_node_id);
self.record(ctor_def_id,
ItemContentBuilder::encode_struct_ctor,
(def_id, item.id, struct_node_id));
}
}
}
fn encode_addl_union_info(&mut self, def_id: DefId) {
self.encode_fields(def_id);
}
fn encode_addl_impl_info(&mut self,
def_id: DefId,
impl_id: ast::NodeId,
ast_items: &[hir::ImplItem]) {
let impl_items = self.tcx.impl_items.borrow();
let items = &impl_items[&def_id];
// 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
};
let trait_item_def_id = trait_item_def_id.def_id();
self.record(trait_item_def_id,
ItemContentBuilder::encode_info_for_impl_item,
(impl_id, trait_item_def_id, ast_item));
}
}
fn encode_addl_trait_info(&mut self,
def_id: DefId,
trait_items: &[hir::TraitItem]) {
// Now output the trait item info for each trait item.
let tcx = self.tcx;
let r = tcx.trait_item_def_ids(def_id);
for (item_def_id, trait_item) in r.iter().zip(trait_items) {
let item_def_id = item_def_id.def_id();
assert!(item_def_id.is_local());
self.record(item_def_id,
ItemContentBuilder::encode_info_for_trait_item,
(def_id, item_def_id, trait_item));
}
}
}
impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> {
fn encode_info_for_foreign_item(&mut self,
(def_id, nitem): (DefId, &hir::ForeignItem)) {
let tcx = self.tcx;
debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
encode_def_id_and_key(self, def_id);
let parent_id = tcx.map.get_parent(nitem.id);
self.encode_parent_item(tcx.map.local_def_id(parent_id));
self.encode_visibility(&nitem.vis);
match nitem.node {
hir::ForeignItemFn(ref fndecl, _) => {
encode_family(self, FN_FAMILY);
self.encode_bounds_and_type_for_item(def_id);
encode_name(self, nitem.name);
encode_attributes(self, &nitem.attrs);
let stab = tcx.lookup_stability(tcx.map.local_def_id(nitem.id));
let depr = tcx.lookup_deprecation(tcx.map.local_def_id(nitem.id));
encode_stability(self, stab);
encode_deprecation(self, depr);
self.encode_method_argument_names(&fndecl);
}
hir::ForeignItemStatic(_, mutbl) => {
if mutbl {
encode_family(self, 'b');
} else {
encode_family(self, 'c');
}
self.encode_bounds_and_type_for_item(def_id);
encode_attributes(self, &nitem.attrs);
let stab = tcx.lookup_stability(tcx.map.local_def_id(nitem.id));
let depr = tcx.lookup_deprecation(tcx.map.local_def_id(nitem.id));
encode_stability(self, stab);
encode_deprecation(self, depr);
encode_name(self, nitem.name);
}
}
}
}
struct EncodeVisitor<'a, 'b: 'a, 'tcx: 'b> {
index: IndexBuilder<'a, 'b, 'tcx>,
}
impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
intravisit::walk_expr(self, ex);
self.index.encode_info_for_expr(ex);
}
fn visit_item(&mut self, item: &'tcx hir::Item) {
intravisit::walk_item(self, item);
let def_id = self.index.tcx.map.local_def_id(item.id);
match item.node {
hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these
_ => self.index.record(def_id,
ItemContentBuilder::encode_info_for_item,
(def_id, item)),
}
self.index.encode_addl_info_for_item(item);
}
fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
intravisit::walk_foreign_item(self, ni);
let def_id = self.index.tcx.map.local_def_id(ni.id);
self.index.record(def_id,
ItemContentBuilder::encode_info_for_foreign_item,
(def_id, ni));
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
intravisit::walk_ty(self, ty);
self.index.encode_info_for_ty(ty);
}
}
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
if let hir::TyImplTrait(_) = ty.node {
let def_id = self.tcx.map.local_def_id(ty.id);
self.record(def_id,
ItemContentBuilder::encode_info_for_anon_ty,
def_id);
}
}
fn encode_info_for_expr(&mut self, expr: &hir::Expr) {
match expr.node {
hir::ExprClosure(..) => {
let def_id = self.tcx.map.local_def_id(expr.id);
self.record(def_id,
ItemContentBuilder::encode_info_for_closure,
def_id);
}
_ => { }
}
}
}
impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> {
fn encode_info_for_anon_ty(&mut self, def_id: DefId) {
encode_def_id_and_key(self, def_id);
encode_family(self, 'y');
self.encode_bounds_and_type_for_item(def_id);
}
fn encode_info_for_closure(&mut self, def_id: DefId) {
let tcx = self.tcx;
encode_def_id_and_key(self, def_id);
encode_name(self, syntax::parse::token::intern("<closure>"));
self.start_tag(tag_items_closure_ty);
tcx.tables.borrow().closure_tys[&def_id].encode(self.ecx).unwrap();
self.end_tag();
self.start_tag(tag_items_closure_kind);
tcx.closure_kind(def_id).encode(self.ecx).unwrap();
self.end_tag();
assert!(self.mir_map.map.contains_key(&def_id));
self.encode_mir(def_id);
}
}
fn encode_info_for_items<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>)
-> (IndexData, FnvHashMap<XRef<'tcx>, u32>) {
let krate = ecx.tcx.map.krate();
ecx.start_tag(tag_items_data);
let fields = {
let mut index = IndexBuilder::new(ecx);
index.record(DefId::local(CRATE_DEF_INDEX),
ItemContentBuilder::encode_info_for_mod,
FromId(CRATE_NODE_ID, (&krate.module,
&[],
syntax::parse::token::intern(&ecx.link_meta.crate_name),
&hir::Public)));
let mut visitor = EncodeVisitor {
index: index,
};
krate.visit_all_items(&mut visitor);
visitor.index.into_fields()
};
ecx.end_tag();
fields
}
fn encode_item_index(ecx: &mut EncodeContext, index: IndexData) {
ecx.start_tag(tag_index);
index.write_index(&mut ecx.opaque.cursor);
ecx.end_tag();
}
fn encode_attributes(ecx: &mut EncodeContext, attrs: &[ast::Attribute]) {
ecx.start_tag(tag_attributes);
attrs.encode(ecx).unwrap();
ecx.end_tag();
}
fn encode_unsafety(ecx: &mut EncodeContext, unsafety: hir::Unsafety) {
let byte: u8 = match unsafety {
hir::Unsafety::Normal => 0,
hir::Unsafety::Unsafe => 1,
};
ecx.wr_tagged_u8(tag_unsafety, byte);
}
fn encode_paren_sugar(ecx: &mut EncodeContext, paren_sugar: bool) {
let byte: u8 = if paren_sugar {1} else {0};
ecx.wr_tagged_u8(tag_paren_sugar, byte);
}
fn encode_defaulted(ecx: &mut EncodeContext, is_defaulted: bool) {
let byte: u8 = if is_defaulted {1} else {0};
ecx.wr_tagged_u8(tag_defaulted_trait, byte);
}
fn encode_associated_type_names(ecx: &mut EncodeContext, names: &[Name]) {
ecx.start_tag(tag_associated_type_names);
for &name in names {
ecx.wr_tagged_str(tag_associated_type_name, &name.as_str());
}
ecx.end_tag();
}
fn encode_polarity(ecx: &mut EncodeContext, polarity: hir::ImplPolarity) {
let byte: u8 = match polarity {
hir::ImplPolarity::Positive => 0,
hir::ImplPolarity::Negative => 1,
};
ecx.wr_tagged_u8(tag_polarity, byte);
}
fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) {
fn get_ordered_deps(cstore: &cstore::CStore)
-> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> {
// 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, CrateNum::new(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.
ecx.start_tag(tag_crate_deps);
for (_cnum, dep) in get_ordered_deps(cstore) {
encode_crate_dep(ecx, &dep);
}
ecx.end_tag();
}
fn encode_lang_items(ecx: &mut EncodeContext) {
ecx.start_tag(tag_lang_items);
for (i, &opt_def_id) in ecx.tcx.lang_items.items().iter().enumerate() {
if let Some(def_id) = opt_def_id {
if def_id.is_local() {
ecx.start_tag(tag_lang_items_item);
ecx.wr_tagged_u32(tag_lang_items_item_id, i as u32);
ecx.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32());
ecx.end_tag();
}
}
}
for i in &ecx.tcx.lang_items.missing {
ecx.wr_tagged_u32(tag_lang_items_missing, *i as u32);
}
ecx.end_tag(); // tag_lang_items
}
fn encode_native_libraries(ecx: &mut EncodeContext) {
ecx.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 => {
ecx.start_tag(tag_native_libraries_lib);
ecx.wr_tagged_u32(tag_native_libraries_kind, kind as u32);
ecx.wr_tagged_str(tag_native_libraries_name, lib);
ecx.end_tag();
}
}
}
ecx.end_tag();
}
fn encode_plugin_registrar_fn(ecx: &mut EncodeContext) {
match ecx.tcx.sess.plugin_registrar_fn.get() {
Some(id) => {
let def_id = ecx.tcx.map.local_def_id(id);
ecx.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32());
}
None => {}
}
}
fn encode_codemap(ecx: &mut EncodeContext) {
ecx.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;
}
ecx.start_tag(tag_codemap_filemap);
filemap.encode(ecx).unwrap();
ecx.end_tag();
}
ecx.end_tag();
}
/// Serialize the text of the exported macros
fn encode_macro_defs(ecx: &mut EncodeContext,
krate: &hir::Crate) {
ecx.start_tag(tag_macro_defs);
for def in &krate.exported_macros {
ecx.start_tag(tag_macro_def);
encode_name(ecx, def.name);
encode_attributes(ecx, &def.attrs);
let &BytePos(lo) = &def.span.lo;
let &BytePos(hi) = &def.span.hi;
ecx.wr_tagged_u32(tag_macro_def_span_lo, lo);
ecx.wr_tagged_u32(tag_macro_def_span_hi, hi);
ecx.wr_tagged_str(tag_macro_def_body,
&::syntax::print::pprust::tts_to_string(&def.body));
ecx.end_tag();
}
ecx.end_tag();
if ecx.tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) {
let id = ecx.tcx.sess.derive_registrar_fn.get().unwrap();
let did = ecx.tcx.map.local_def_id(id);
ecx.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32());
}
}
fn encode_struct_field_attrs(ecx: &mut EncodeContext, krate: &hir::Crate) {
struct StructFieldVisitor<'a, 'b:'a, 'tcx:'b> {
ecx: &'a mut EncodeContext<'b, 'tcx>
}
impl<'a, 'b, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'tcx> {
fn visit_struct_field(&mut self, field: &hir::StructField) {
self.ecx.start_tag(tag_struct_field);
let def_id = self.ecx.tcx.map.local_def_id(field.id);
encode_def_id(self.ecx, def_id);
encode_attributes(self.ecx, &field.attrs);
self.ecx.end_tag();
}
}
ecx.start_tag(tag_struct_fields);
krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx });
ecx.end_tag();
}
struct ImplVisitor<'a, 'tcx:'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
impls: FnvHashMap<DefId, Vec<DefId>>
}
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(ecx: &mut EncodeContext, krate: &hir::Crate) {
let mut visitor = ImplVisitor {
tcx: ecx.tcx,
impls: FnvHashMap()
};
krate.visit_all_items(&mut visitor);
ecx.start_tag(tag_impls);
for (trait_, trait_impls) in visitor.impls {
ecx.start_tag(tag_impls_trait);
encode_def_id(ecx, trait_);
for impl_ in trait_impls {
ecx.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_));
}
ecx.end_tag();
}
ecx.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: &mut EncodeContext) {
ecx.start_tag(tag_reachable_ids);
for &id in ecx.reachable {
let def_id = ecx.tcx.map.local_def_id(id);
ecx.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32());
}
ecx.end_tag();
}
fn encode_crate_dep(ecx: &mut EncodeContext,
dep: &cstore::CrateMetadata) {
ecx.start_tag(tag_crate_dep);
ecx.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
let hash = decoder::get_crate_hash(dep.data());
ecx.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64());
ecx.wr_tagged_u8(tag_crate_dep_explicitly_linked,
dep.explicitly_linked.get() as u8);
ecx.end_tag();
}
fn encode_hash(ecx: &mut EncodeContext, hash: &Svh) {
ecx.wr_tagged_u64(tag_crate_hash, hash.as_u64());
}
fn encode_rustc_version(ecx: &mut EncodeContext) {
ecx.wr_tagged_str(tag_rustc_version, &rustc_version());
}
fn encode_crate_name(ecx: &mut EncodeContext, crate_name: &str) {
ecx.wr_tagged_str(tag_crate_crate_name, crate_name);
}
fn encode_crate_disambiguator(ecx: &mut EncodeContext, crate_disambiguator: &str) {
ecx.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator);
}
fn encode_crate_triple(ecx: &mut EncodeContext, triple: &str) {
ecx.wr_tagged_str(tag_crate_triple, triple);
}
fn encode_dylib_dependency_formats(ecx: &mut 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::<Vec<String>>();
ecx.wr_tagged_str(tag, &s.join(","));
}
None => {
ecx.wr_tagged_str(tag, "");
}
}
}
fn encode_panic_strategy(ecx: &mut EncodeContext) {
match ecx.tcx.sess.opts.cg.panic {
PanicStrategy::Unwind => {
ecx.wr_tagged_u8(tag_panic_strategy, b'U');
}
PanicStrategy::Abort => {
ecx.wr_tagged_u8(tag_panic_strategy, b'A');
}
}
}
pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
cstore: &cstore::CStore,
reexports: &def::ExportMap,
link_meta: &LinkMeta,
reachable: &NodeSet,
mir_map: &MirMap<'tcx>) -> Vec<u8> {
let mut cursor = Cursor::new(vec![]);
cursor.write_all(&[0, 0, 0, 0]).unwrap();
cursor.write_all(metadata_encoding_version).unwrap();
// Will be filed with the length after encoding the crate.
cursor.write_all(&[0, 0, 0, 0]).unwrap();
encode_metadata_inner(&mut EncodeContext {
rbml_w: rbml::writer::Encoder::new(&mut cursor),
tcx: tcx,
reexports: reexports,
link_meta: link_meta,
cstore: cstore,
reachable: reachable,
mir_map: mir_map,
type_shorthands: Default::default(),
});
// RBML compacts the encoded bytes whenever appropriate,
// so there are some garbages left after the end of the data.
let meta_len = cursor.position() as usize;
cursor.get_mut().truncate(meta_len);
// 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.
//
// We also need to store the metadata encoding version here, because
// rlibs don't have it. To get older versions of rustc to ignore
// this metadata, there are 4 zero bytes at the start, which are
// treated as a length of 0 by old compilers.
let meta_start = 8 + ::common::metadata_encoding_version.len();
let len = meta_len - meta_start;
let mut result = cursor.into_inner();
result[meta_start - 4] = (len >> 24) as u8;
result[meta_start - 3] = (len >> 16) as u8;
result[meta_start - 2] = (len >> 8) as u8;
result[meta_start - 1] = (len >> 0) as u8;
result
}
fn encode_metadata_inner(ecx: &mut EncodeContext) {
encode_rustc_version(ecx);
let tcx = ecx.tcx;
let link_meta = ecx.link_meta;
encode_crate_name(ecx, &link_meta.crate_name);
encode_crate_triple(ecx, &tcx.sess.opts.target_triple);
encode_hash(ecx, &link_meta.crate_hash);
encode_crate_disambiguator(ecx, &tcx.sess.local_crate_disambiguator());
encode_dylib_dependency_formats(ecx);
encode_panic_strategy(ecx);
let krate = tcx.map.krate();
let mut i = ecx.position();
encode_attributes(ecx, &krate.attrs);
let attr_bytes = ecx.position() - i;
i = ecx.position();
encode_crate_deps(ecx, ecx.cstore);
let dep_bytes = ecx.position() - i;
// Encode the language items.
i = ecx.position();
encode_lang_items(ecx);
let lang_item_bytes = ecx.position() - i;
// Encode the native libraries used
i = ecx.position();
encode_native_libraries(ecx);
let native_lib_bytes = ecx.position() - i;
// Encode the plugin registrar function
i = ecx.position();
encode_plugin_registrar_fn(ecx);
let plugin_registrar_fn_bytes = ecx.position() - i;
// Encode codemap
i = ecx.position();
encode_codemap(ecx);
let codemap_bytes = ecx.position() - i;
// Encode macro definitions
i = ecx.position();
encode_macro_defs(ecx, krate);
let macro_defs_bytes = ecx.position() - i;
// Encode the def IDs of impls, for coherence checking.
i = ecx.position();
encode_impls(ecx, krate);
let impl_bytes = ecx.position() - i;
// Encode reachability info.
i = ecx.position();
encode_reachable(ecx);
let reachable_bytes = ecx.position() - i;
// Encode and index the items.
ecx.start_tag(tag_items);
i = ecx.position();
let (items, xrefs) = encode_info_for_items(ecx);
let item_bytes = ecx.position() - i;
ecx.end_tag();
i = ecx.position();
encode_item_index(ecx, items);
let index_bytes = ecx.position() - i;
i = ecx.position();
encode_xrefs(ecx, xrefs);
let xref_bytes = ecx.position() - i;
encode_struct_field_attrs(ecx, krate);
let total_bytes = ecx.position();
if ecx.tcx.sess.meta_stats() {
let mut zero_bytes = 0;
for e in ecx.opaque.cursor.get_ref() {
if *e == 0 {
zero_bytes += 1;
}
}
println!("metadata stats:");
println!(" attribute bytes: {}", attr_bytes);
println!(" dep bytes: {}", dep_bytes);
println!(" lang item bytes: {}", lang_item_bytes);
println!(" native bytes: {}", native_lib_bytes);
println!("plugin registrar bytes: {}", plugin_registrar_fn_bytes);
println!(" codemap bytes: {}", codemap_bytes);
println!(" macro def bytes: {}", macro_defs_bytes);
println!(" impl bytes: {}", impl_bytes);
println!(" reachable bytes: {}", reachable_bytes);
println!(" item bytes: {}", item_bytes);
println!(" index bytes: {}", index_bytes);
println!(" xref bytes: {}", xref_bytes);
println!(" zero bytes: {}", zero_bytes);
println!(" total bytes: {}", total_bytes);
}
}