Rollup merge of #35114 - michaelwoerister:inline-meta-to-hir-map, r=eddyb
Move caching of inlined HIR into CrateStore So far we've had separate HIR-inlining caches for each codegen unit and the caching for things inlined during constant evaluation had some holes. Consequently, things would be inlined multiple times if they were used from different codegen units, etc, leading to - wasted memory, - multiple `NodeId`s per `DefId` and, - for things inlined during constant evaluation, no way to map a `NodeId` back to it's original `DefId`. This PR moves all caching into the CrateStore, solving all of the above problems. It also fixes some bugs in the inlining code, like cyclic in the parent-chains in the HIR map and some `NodeId`'s being translated to more or less random values. There are assertions in place now that should prevent this kind of thing in the future. This PR based on top of #35090, which contains some necessary fixes.
This commit is contained in:
commit
518524de1a
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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("e_item!(&cx,
|
||||
fn new_int_alist<B>() -> alist<isize, B> {
|
||||
return alist {eq_fn: eq_int, data: Vec::new()};
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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>> {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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() {
|
||||
|
@ -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 }
|
||||
|
Loading…
x
Reference in New Issue
Block a user