Move caching of HIR-inlining into CStore in order to avoid duplicating inlined HIR.

This commit is contained in:
Michael Woerister 2016-07-26 10:58:35 -04:00
parent 535cea0eec
commit d5a5149617
17 changed files with 335 additions and 175 deletions

View File

@ -867,7 +867,7 @@ pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) {
}
}
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)]
pub struct IdRange {
pub min: NodeId,
pub max: NodeId,
@ -893,6 +893,7 @@ impl IdRange {
self.min = cmp::min(self.min, id);
self.max = cmp::max(self.max, id + 1);
}
}

View File

@ -32,6 +32,7 @@ use hir::print as pprust;
use arena::TypedArena;
use std::cell::RefCell;
use std::cmp;
use std::io;
use std::mem;
@ -127,7 +128,10 @@ impl<'ast> MapEntry<'ast> {
EntryStructCtor(id, _) => id,
EntryLifetime(id, _) => id,
EntryTyParam(id, _) => id,
_ => return None
NotPresent |
RootCrate |
RootInlinedParent(_) => return None,
})
}
@ -196,6 +200,10 @@ pub struct Map<'ast> {
map: RefCell<Vec<MapEntry<'ast>>>,
definitions: RefCell<Definitions>,
/// All NodeIds that are numerically greater or equal to this value come
/// from inlined items.
local_node_id_watermark: NodeId,
}
impl<'ast> Map<'ast> {
@ -550,6 +558,13 @@ impl<'ast> Map<'ast> {
}
}
pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem {
match self.find_entry(id) {
Some(RootInlinedParent(inlined_item)) => inlined_item,
_ => bug!("expected inlined item, found {}", self.node_to_string(id)),
}
}
/// Returns the name associated with the given NodeId's AST.
pub fn name(&self, id: NodeId) -> Name {
match self.get(id) {
@ -649,6 +664,10 @@ impl<'ast> Map<'ast> {
pub fn node_to_user_string(&self, id: NodeId) -> String {
node_id_to_string(self, id, false)
}
pub fn is_inlined(&self, id: NodeId) -> bool {
id >= self.local_node_id_watermark
}
}
pub struct NodesMatchingSuffix<'a, 'ast:'a> {
@ -765,13 +784,37 @@ pub trait FoldOps {
}
/// A Folder that updates IDs and Span's according to fold_ops.
struct IdAndSpanUpdater<F> {
fold_ops: F
pub struct IdAndSpanUpdater<F> {
fold_ops: F,
min_id_assigned: NodeId,
max_id_assigned: NodeId,
}
impl<F: FoldOps> IdAndSpanUpdater<F> {
pub fn new(fold_ops: F) -> IdAndSpanUpdater<F> {
IdAndSpanUpdater {
fold_ops: fold_ops,
min_id_assigned: ::std::u32::MAX,
max_id_assigned: ::std::u32::MIN,
}
}
pub fn id_range(&self) -> intravisit::IdRange {
intravisit::IdRange {
min: self.min_id_assigned,
max: self.max_id_assigned + 1,
}
}
}
impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
fn new_id(&mut self, id: NodeId) -> NodeId {
self.fold_ops.new_id(id)
let id = self.fold_ops.new_id(id);
self.min_id_assigned = cmp::min(self.min_id_assigned, id);
self.max_id_assigned = cmp::max(self.max_id_assigned, id);
id
}
fn new_span(&mut self, span: Span) -> Span {
@ -802,11 +845,14 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
}
let local_node_id_watermark = map.len() as NodeId;
Map {
forest: forest,
dep_graph: forest.dep_graph.clone(),
map: RefCell::new(map),
definitions: RefCell::new(definitions),
local_node_id_watermark: local_node_id_watermark
}
}
@ -818,7 +864,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
ii: InlinedItem,
fold_ops: F)
-> &'ast InlinedItem {
let mut fld = IdAndSpanUpdater { fold_ops: fold_ops };
let mut fld = IdAndSpanUpdater::new(fold_ops);
let ii = match ii {
II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))),
II::TraitItem(d, ti) => {
@ -835,6 +881,12 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
let ii = map.forest.inlined_items.alloc(ii);
let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
// Assert that the ii_parent_id is the last NodeId in our reserved range
assert!(ii_parent_id == fld.max_id_assigned);
// Assert that we did not violate the invariant that all inlined HIR items
// have NodeIds greater than or equal to `local_node_id_watermark`
assert!(fld.min_id_assigned >= map.local_node_id_watermark);
let defs = &mut *map.definitions.borrow_mut();
let mut def_collector = DefCollector::extend(ii_parent_id,
parent_def_path.clone(),

View File

@ -120,12 +120,6 @@ pub struct ChildItem {
pub vis: ty::Visibility,
}
pub enum FoundAst<'ast> {
Found(&'ast InlinedItem),
FoundParent(DefId, &'ast hir::Item),
NotFound,
}
#[derive(Copy, Clone, Debug)]
pub struct ExternCrate {
/// def_id of an `extern crate` in the current crate that caused
@ -250,7 +244,10 @@ pub trait CrateStore<'tcx> {
// misc. metadata
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> FoundAst<'tcx>;
-> Option<(&'tcx InlinedItem, ast::NodeId)>;
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>;
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<Mir<'tcx>>;
fn is_item_mir_available(&self, def: DefId) -> bool;
@ -447,7 +444,16 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
// misc. metadata
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> FoundAst<'tcx> { bug!("maybe_get_item_ast") }
-> Option<(&'tcx InlinedItem, ast::NodeId)> {
bug!("maybe_get_item_ast")
}
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
bug!("local_node_for_inlined_defid")
}
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
bug!("defid_for_inlined_node")
}
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<Mir<'tcx>> { bug!("maybe_get_item_mir") }
fn is_item_mir_available(&self, def: DefId) -> bool {

View File

@ -17,7 +17,7 @@ use self::EvalHint::*;
use rustc::hir::map as ast_map;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::cstore::{self, InlinedItem};
use rustc::middle::cstore::InlinedItem;
use rustc::traits;
use rustc::hir::def::{Def, PathResolution};
use rustc::hir::def_id::DefId;
@ -142,13 +142,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
let mut used_substs = false;
let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
Some((&InlinedItem::Item(ref item), _)) => match item.node {
hir::ItemConst(ref ty, ref const_expr) => {
Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
},
_ => None
},
cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node {
Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
hir::ConstTraitItem(_, _) => {
used_substs = true;
if let Some(substs) = substs {
@ -163,7 +163,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
_ => None
},
cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node {
Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node {
hir::ImplItemKind::Const(ref ty, ref expr) => {
Some((&**expr, tcx.ast_ty_to_prim_ty(ty)))
},
@ -198,8 +198,8 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id),
cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id),
Some((&InlinedItem::Item(ref item), _)) => Some(item.id),
Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
_ => None
};
tcx.extern_const_fns.borrow_mut().insert(def_id,

View File

@ -88,8 +88,9 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
rbml_w.writer.seek(SeekFrom::Current(0)));
// Folding could be avoided with a smarter encoder.
let ii = simplify_ast(ii);
let (ii, expected_id_range) = simplify_ast(ii);
let id_range = inlined_item_id_range(&ii);
assert_eq!(expected_id_range, id_range);
rbml_w.start_tag(c::tag_ast as usize);
id_range.encode(rbml_w);
@ -186,6 +187,10 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId {
// from_id_range should be non-empty
assert!(!self.from_id_range.empty());
// Make sure that translating the NodeId will actually yield a
// meaningful result
assert!(self.from_id_range.contains(id));
// 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))
@ -279,9 +284,23 @@ fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) {
rbml_w.end_tag();
}
struct NestedItemsDropper;
struct NestedItemsDropper {
id_range: IdRange
}
impl Folder for NestedItemsDropper {
// The unit tests below run on HIR with NodeIds not properly assigned. That
// causes an integer overflow. So we just don't track the id_range when
// building the unit tests.
#[cfg(not(test))]
fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
// Record the range of NodeIds we are visiting, so we can do a sanity
// check later
self.id_range.add(id);
id
}
fn fold_block(&mut self, blk: P<hir::Block>) -> P<hir::Block> {
blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| {
let stmts_sans_items = stmts.into_iter().filter_map(|stmt| {
@ -322,10 +341,12 @@ impl Folder for NestedItemsDropper {
// 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;
fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) {
let mut fld = NestedItemsDropper {
id_range: IdRange::max()
};
match ii {
let ii = match ii {
// HACK we're not dropping items.
InlinedItemRef::Item(i) => {
InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld)))
@ -339,7 +360,9 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
InlinedItemRef::Foreign(i) => {
InlinedItem::Foreign(P(fold::noop_fold_foreign_item(i.clone(), &mut fld)))
}
}
};
(ii, fld.id_range)
}
fn decode_ast(item_doc: rbml::Doc) -> InlinedItem {
@ -361,8 +384,18 @@ impl tr for Def {
match *self {
Def::Fn(did) => Def::Fn(did.tr(dcx)),
Def::Method(did) => Def::Method(did.tr(dcx)),
Def::SelfTy(opt_did, impl_id) => { Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
impl_id.map(|id| dcx.tr_id(id))) }
Def::SelfTy(opt_did, impl_id) => {
// Since the impl_id will never lie within the reserved range of
// imported NodeIds, it does not make sense to translate it.
// The result would not make any sense within the importing crate.
// We also don't allow for impl items to be inlined (just their
// members), so even if we had a DefId here, we wouldn't be able
// to do much with it.
// So, we set the id to DUMMY_NODE_ID. That way we make it
// explicit that this is no usable NodeId.
Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
impl_id.map(|_| ast::DUMMY_NODE_ID))
}
Def::Mod(did) => { Def::Mod(did.tr(dcx)) }
Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) }
Def::Static(did, m) => { Def::Static(did.tr(dcx), m) }
@ -1361,7 +1394,7 @@ fn test_simplification() {
with_testing_context(|lcx| {
let hir_item = lcx.lower_item(&item);
let item_in = InlinedItemRef::Item(&hir_item);
let item_out = simplify_ast(item_in);
let (item_out, _) = simplify_ast(item_in);
let item_exp = InlinedItem::Item(P(lcx.lower_item(&quote_item!(&cx,
fn new_int_alist<B>() -> alist<isize, B> {
return alist {eq_fn: eq_int, data: Vec::new()};

View File

@ -14,7 +14,7 @@ use decoder;
use encoder;
use loader;
use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst, DefLike};
use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate, DefLike};
use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
use rustc::hir::def;
use middle::lang_items;
@ -482,12 +482,146 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
result
}
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> FoundAst<'tcx>
fn maybe_get_item_ast<'a>(&'tcx self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Option<(&'tcx InlinedItem, ast::NodeId)>
{
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::maybe_get_item_ast(&cdata, tcx, def.index)
self.dep_graph.read(DepNode::MetaData(def_id));
match self.inlined_item_cache.borrow().get(&def_id) {
Some(&None) => {
return None; // Not inlinable
}
Some(&Some(ref cached_inlined_item)) => {
// Already inline
debug!("maybe_get_item_ast({}): already inline as node id {}",
tcx.item_path_str(def_id), cached_inlined_item.item_id);
return Some((tcx.map.expect_inlined_item(cached_inlined_item.inlined_root),
cached_inlined_item.item_id));
}
None => {
// Not seen yet
}
}
debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id));
let cdata = self.get_crate_data(def_id.krate);
let inlined = decoder::maybe_get_item_ast(&cdata, tcx, def_id.index);
let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| {
let cache_entry = cstore::CachedInlinedItem {
inlined_root: inlined_root_node_id,
item_id: inlined_item_id,
};
self.inlined_item_cache
.borrow_mut()
.insert(original_def_id, Some(cache_entry));
self.defid_for_inlined_node
.borrow_mut()
.insert(inlined_item_id, original_def_id);
};
let find_inlined_item_root = |inlined_item_id| {
let mut node = inlined_item_id;
let mut path = Vec::with_capacity(10);
// If we can't find the inline root after a thousand hops, we can
// be pretty sure there's something wrong with the HIR map.
for _ in 0 .. 1000 {
path.push(node);
let parent_node = tcx.map.get_parent_node(node);
if parent_node == node {
return node;
}
node = parent_node;
}
bug!("cycle in HIR map parent chain")
};
match inlined {
decoder::FoundAst::NotFound => {
self.inlined_item_cache
.borrow_mut()
.insert(def_id, None);
}
decoder::FoundAst::Found(&InlinedItem::Item(ref item)) => {
let inlined_root_node_id = find_inlined_item_root(item.id);
cache_inlined_item(def_id, item.id, inlined_root_node_id);
}
decoder::FoundAst::Found(&InlinedItem::Foreign(ref item)) => {
let inlined_root_node_id = find_inlined_item_root(item.id);
cache_inlined_item(def_id, item.id, inlined_root_node_id);
}
decoder::FoundAst::FoundParent(parent_did, item) => {
let inlined_root_node_id = find_inlined_item_root(item.id);
cache_inlined_item(parent_did, item.id, inlined_root_node_id);
match item.node {
hir::ItemEnum(ref ast_def, _) => {
let ast_vs = &ast_def.variants;
let ty_vs = &tcx.lookup_adt_def(parent_did).variants;
assert_eq!(ast_vs.len(), ty_vs.len());
for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) {
cache_inlined_item(ty_v.did,
ast_v.node.data.id(),
inlined_root_node_id);
}
}
hir::ItemStruct(ref struct_def, _) => {
if struct_def.is_struct() {
bug!("instantiate_inline: called on a non-tuple struct")
} else {
cache_inlined_item(def_id,
struct_def.id(),
inlined_root_node_id);
}
}
_ => bug!("instantiate_inline: item has a \
non-enum, non-struct parent")
}
}
decoder::FoundAst::Found(&InlinedItem::TraitItem(_, ref trait_item)) => {
let inlined_root_node_id = find_inlined_item_root(trait_item.id);
cache_inlined_item(def_id, trait_item.id, inlined_root_node_id);
// Associated consts already have to be evaluated in `typeck`, so
// the logic to do that already exists in `middle`. In order to
// reuse that code, it needs to be able to look up the traits for
// inlined items.
let ty_trait_item = tcx.impl_or_trait_item(def_id).clone();
let trait_item_def_id = tcx.map.local_def_id(trait_item.id);
tcx.impl_or_trait_items.borrow_mut()
.insert(trait_item_def_id, ty_trait_item);
}
decoder::FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => {
let inlined_root_node_id = find_inlined_item_root(impl_item.id);
cache_inlined_item(def_id, impl_item.id, inlined_root_node_id);
}
}
// We can be sure to hit the cache now
return self.maybe_get_item_ast(tcx, def_id);
}
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
assert!(!def_id.is_local());
match self.inlined_item_cache.borrow().get(&def_id) {
Some(&Some(ref cached_inlined_item)) => {
Some(cached_inlined_item.item_id)
}
Some(&None) => {
None
}
_ => {
bug!("Trying to lookup inlined NodeId for unexpected item");
}
}
}
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
self.defid_for_inlined_node.borrow().get(&node_id).map(|x| *x)
}
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
@ -634,3 +768,4 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
visible_parent_map
}
}

View File

@ -25,7 +25,7 @@ use rustc::dep_graph::DepGraph;
use rustc::hir::def_id::{DefIndex, DefId};
use rustc::hir::map::DefKey;
use rustc::hir::svh::Svh;
use rustc::middle::cstore::{ExternCrate};
use rustc::middle::cstore::ExternCrate;
use rustc::session::config::PanicStrategy;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
@ -96,6 +96,13 @@ pub struct CrateMetadata {
pub explicitly_linked: Cell<bool>,
}
pub struct CachedInlinedItem {
/// The NodeId of the RootInlinedParent HIR map entry
pub inlined_root: ast::NodeId,
/// The local NodeId of the inlined entity
pub item_id: ast::NodeId,
}
pub struct CStore {
pub dep_graph: DepGraph,
metas: RefCell<FnvHashMap<ast::CrateNum, Rc<CrateMetadata>>>,
@ -105,6 +112,8 @@ pub struct CStore {
used_libraries: RefCell<Vec<(String, NativeLibraryKind)>>,
used_link_args: RefCell<Vec<String>>,
statically_included_foreign_items: RefCell<NodeSet>,
pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
}
@ -119,6 +128,8 @@ impl CStore {
used_link_args: RefCell::new(Vec::new()),
statically_included_foreign_items: RefCell::new(NodeSet()),
visible_parent_map: RefCell::new(FnvHashMap()),
inlined_item_cache: RefCell::new(FnvHashMap()),
defid_for_inlined_node: RefCell::new(FnvHashMap()),
}
}

View File

@ -30,7 +30,7 @@ use rustc::util::nodemap::FnvHashMap;
use rustc::hir;
use rustc::session::config::PanicStrategy;
use middle::cstore::{FoundAst, InlinedItem, LinkagePreference};
use middle::cstore::{InlinedItem, LinkagePreference};
use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
use rustc::hir::def::Def;
use rustc::hir::def_id::{DefId, DefIndex};
@ -755,6 +755,12 @@ pub fn maybe_get_item_name(cdata: Cmd, id: DefIndex) -> Option<ast::Name> {
maybe_item_name(cdata.lookup_item(id))
}
pub enum FoundAst<'ast> {
Found(&'ast InlinedItem),
FoundParent(DefId, &'ast hir::Item),
NotFound,
}
pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex)
-> FoundAst<'tcx> {
debug!("Looking up item: {:?}", id);

View File

@ -1235,7 +1235,6 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
inlined_vid: ast::NodeId)
-> ty::VariantDef<'tcx>
{
let ctor_ty = ccx.tcx().node_id_to_type(inlined_vid);
debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty,
inlined_vid);
@ -1245,13 +1244,18 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}), ..}) => ty,
_ => ctor_ty
}.ty_adt_def().unwrap();
let inlined_vid_def_id = ccx.tcx().map.local_def_id(inlined_vid);
adt_def.variants.iter().find(|v| {
inlined_vid_def_id == v.did ||
ccx.external().borrow().get(&v.did) == Some(&Some(inlined_vid))
}).unwrap_or_else(|| {
bug!("no variant for {:?}::{}", adt_def, inlined_vid)
})
let variant_def_id = if ccx.tcx().map.is_inlined(inlined_vid) {
ccx.defid_for_inlined_node(inlined_vid).unwrap()
} else {
ccx.tcx().map.local_def_id(inlined_vid)
};
adt_def.variants
.iter()
.find(|v| variant_def_id == v.did)
.unwrap_or_else(|| {
bug!("no variant for {:?}::{}", adt_def, inlined_vid)
})
}
// To avoid UB from LLVM, these two functions mask RHS with an

View File

@ -1026,7 +1026,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
.get(TransItem::Static(id))
.expect("Local statics should always be in the SymbolMap");
// Make sure that this is never executed for something inlined.
assert!(!ccx.external_srcs().borrow().contains_key(&id));
assert!(!ccx.tcx().map.is_inlined(id));
let defined_in_current_codegen_unit = ccx.codegen_unit()
.items()

View File

@ -36,7 +36,7 @@ use session::config::NoDebugInfo;
use session::Session;
use symbol_map::SymbolMap;
use util::sha2::Sha256;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
use util::nodemap::{NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
@ -101,11 +101,6 @@ pub struct LocalCrateContext<'tcx> {
needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, (ValueRef, FnType)>>,
/// Track mapping of external ids to local items imported for inlining
external: RefCell<DefIdMap<Option<ast::NodeId>>>,
/// Backwards version of the `external` map (inlined items to where they
/// came from)
external_srcs: RefCell<NodeMap<DefId>>,
/// Cache instances of monomorphic and polymorphic items
instances: RefCell<FnvHashMap<Instance<'tcx>, ValueRef>>,
monomorphizing: RefCell<DefIdMap<usize>>,
@ -572,8 +567,6 @@ impl<'tcx> LocalCrateContext<'tcx> {
needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()),
fn_pointer_shims: RefCell::new(FnvHashMap()),
drop_glues: RefCell::new(FnvHashMap()),
external: RefCell::new(DefIdMap()),
external_srcs: RefCell::new(NodeMap()),
instances: RefCell::new(FnvHashMap()),
monomorphizing: RefCell::new(DefIdMap()),
vtables: RefCell::new(FnvHashMap()),
@ -767,12 +760,12 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local().drop_glues
}
pub fn external<'a>(&'a self) -> &'a RefCell<DefIdMap<Option<ast::NodeId>>> {
&self.local().external
pub fn local_node_for_inlined_defid<'a>(&'a self, def_id: DefId) -> Option<ast::NodeId> {
self.sess().cstore.local_node_for_inlined_defid(def_id)
}
pub fn external_srcs<'a>(&'a self) -> &'a RefCell<NodeMap<DefId>> {
&self.local().external_srcs
pub fn defid_for_inlined_node<'a>(&'a self, node_id: ast::NodeId) -> Option<DefId> {
self.sess().cstore.defid_for_inlined_node(node_id)
}
pub fn instances<'a>(&'a self) -> &'a RefCell<FnvHashMap<Instance<'tcx>, ValueRef>> {

View File

@ -326,13 +326,12 @@ impl<'tcx> TypeMap<'tcx> {
// First, find out the 'real' def_id of the type. Items inlined from
// other crates have to be mapped back to their source.
let def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) {
match cx.external_srcs().borrow().get(&node_id).cloned() {
Some(source_def_id) => {
// The given def_id identifies the inlined copy of a
// type definition, let's take the source of the copy.
source_def_id
}
None => def_id
if cx.tcx().map.is_inlined(node_id) {
// The given def_id identifies the inlined copy of a
// type definition, let's take the source of the copy.
cx.defid_for_inlined_node(node_id).unwrap()
} else {
def_id
}
} else {
def_id
@ -1842,7 +1841,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
// crate should already contain debuginfo for it. More importantly, the
// global might not even exist in un-inlined form anywhere which would lead
// to a linker errors.
if cx.external_srcs().borrow().contains_key(&node_id) {
if cx.tcx().map.is_inlined(node_id) {
return;
}

View File

@ -439,10 +439,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
});
// Try to get some span information, if we have an inlined item.
let definition_span = match cx.external().borrow().get(&instance.def) {
Some(&Some(node_id)) => cx.tcx().map.span(node_id),
_ => cx.tcx().map.def_id_span(instance.def, syntax_pos::DUMMY_SP)
};
let definition_span = cx.tcx()
.map
.def_id_span(instance.def, syntax_pos::DUMMY_SP);
(containing_scope, definition_span)
}

View File

@ -86,10 +86,7 @@ pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
});
// Try to get some span information, if we have an inlined item.
let definition_span = match cx.external().borrow().get(&def_id) {
Some(&Some(node_id)) => cx.tcx().map.span(node_id),
_ => cx.tcx().map.def_id_span(def_id, syntax_pos::DUMMY_SP)
};
let definition_span = cx.tcx().map.def_id_span(def_id, syntax_pos::DUMMY_SP);
(containing_scope, definition_span)
}

View File

@ -8,14 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use middle::cstore::{FoundAst, InlinedItem};
use rustc::hir::def_id::DefId;
use base::push_ctxt;
use common::*;
use monomorphize::Instance;
use rustc::dep_graph::DepNode;
use rustc::hir;
fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option<DefId> {
debug!("instantiate_inline({:?})", fn_id);
@ -23,104 +21,12 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option<DefId> {
let tcx = ccx.tcx();
let _task = tcx.dep_graph.in_task(DepNode::TransInlinedItem(fn_id));
match ccx.external().borrow().get(&fn_id) {
Some(&Some(node_id)) => {
// Already inline
debug!("instantiate_inline({}): already inline as node id {}",
tcx.item_path_str(fn_id), node_id);
let node_def_id = tcx.map.local_def_id(node_id);
return Some(node_def_id);
}
Some(&None) => {
return None; // Not inlinable
}
None => {
// Not seen yet
}
}
let inlined = tcx.sess.cstore.maybe_get_item_ast(tcx, fn_id);
let inline_id = match inlined {
FoundAst::NotFound => {
ccx.external().borrow_mut().insert(fn_id, None);
return None;
}
FoundAst::Found(&InlinedItem::Item(ref item)) => {
ccx.external().borrow_mut().insert(fn_id, Some(item.id));
ccx.external_srcs().borrow_mut().insert(item.id, fn_id);
ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
item.id
}
FoundAst::Found(&InlinedItem::Foreign(ref item)) => {
ccx.external().borrow_mut().insert(fn_id, Some(item.id));
ccx.external_srcs().borrow_mut().insert(item.id, fn_id);
item.id
}
FoundAst::FoundParent(parent_id, item) => {
ccx.external().borrow_mut().insert(parent_id, Some(item.id));
ccx.external_srcs().borrow_mut().insert(item.id, parent_id);
let mut my_id = 0;
match item.node {
hir::ItemEnum(ref ast_def, _) => {
let ast_vs = &ast_def.variants;
let ty_vs = &tcx.lookup_adt_def(parent_id).variants;
assert_eq!(ast_vs.len(), ty_vs.len());
for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) {
if ty_v.did == fn_id { my_id = ast_v.node.data.id(); }
ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id()));
ccx.external_srcs().borrow_mut().insert(ast_v.node.data.id(), ty_v.did);
}
}
hir::ItemStruct(ref struct_def, _) => {
if struct_def.is_struct() {
bug!("instantiate_inline: called on a \
non-tuple struct")
} else {
ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id()));
ccx.external_srcs().borrow_mut().insert(struct_def.id(), fn_id);
my_id = struct_def.id();
}
}
_ => bug!("instantiate_inline: item has a \
non-enum, non-struct parent")
}
my_id
}
FoundAst::Found(&InlinedItem::TraitItem(_, ref trait_item)) => {
ccx.external().borrow_mut().insert(fn_id, Some(trait_item.id));
ccx.external_srcs().borrow_mut().insert(trait_item.id, fn_id);
ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
// Associated consts already have to be evaluated in `typeck`, so
// the logic to do that already exists in `middle`. In order to
// reuse that code, it needs to be able to look up the traits for
// inlined items.
let ty_trait_item = tcx.impl_or_trait_item(fn_id).clone();
let trait_item_def_id = tcx.map.local_def_id(trait_item.id);
tcx.impl_or_trait_items.borrow_mut()
.insert(trait_item_def_id, ty_trait_item);
// If this is a default method, we can't look up the
// impl type. But we aren't going to translate anyways, so
// don't.
trait_item.id
}
FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => {
ccx.external().borrow_mut().insert(fn_id, Some(impl_item.id));
ccx.external_srcs().borrow_mut().insert(impl_item.id, fn_id);
ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
impl_item.id
}
};
let inline_def_id = tcx.map.local_def_id(inline_id);
Some(inline_def_id)
tcx.sess
.cstore
.maybe_get_item_ast(tcx, fn_id)
.map(|(_, inline_id)| {
tcx.map.local_def_id(inline_id)
})
}
pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId)

View File

@ -1313,6 +1313,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
// item is declared.
let bound = match (&ty.sty, ty_path_def) {
(_, Def::SelfTy(Some(trait_did), Some(impl_id))) => {
// For Def::SelfTy() values inlined from another crate, the
// impl_id will be DUMMY_NODE_ID, which would cause problems
// here. But we should never run into an impl from another crate
// in this pass.
assert!(impl_id != ast::DUMMY_NODE_ID);
// `Self` in an impl of a trait - we have a concrete self type and a
// trait reference.
let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap();
@ -1518,6 +1524,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
}
Def::SelfTy(_, Some(impl_id)) => {
// Self in impl (we know the concrete type).
// For Def::SelfTy() values inlined from another crate, the
// impl_id will be DUMMY_NODE_ID, which would cause problems
// here. But we should never run into an impl from another crate
// in this pass.
assert!(impl_id != ast::DUMMY_NODE_ID);
tcx.prohibit_type_params(base_segments);
let ty = tcx.node_id_to_type(impl_id);
if let Some(free_substs) = self.get_free_substs() {

View File

@ -2691,7 +2691,12 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
Def::Static(i, _) => (i, TypeStatic),
Def::Variant(i, _) => (i, TypeEnum),
Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait),
Def::SelfTy(_, Some(impl_id)) => return cx.map.local_def_id(impl_id),
Def::SelfTy(_, Some(impl_id)) => {
// For Def::SelfTy() values inlined from another crate, the
// impl_id will be DUMMY_NODE_ID, which would cause problems.
// But we should never run into an impl from another crate here.
return cx.map.local_def_id(impl_id)
}
_ => return def.def_id()
};
if did.is_local() { return did }