Skip to content

Commit 518524d

Browse files
authored
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.
2 parents 05a2d39 + d5a5149 commit 518524d

File tree

17 files changed

+335
-175
lines changed

17 files changed

+335
-175
lines changed

src/librustc/hir/intravisit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) {
867867
}
868868
}
869869

870-
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
870+
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)]
871871
pub struct IdRange {
872872
pub min: NodeId,
873873
pub max: NodeId,
@@ -893,6 +893,7 @@ impl IdRange {
893893
self.min = cmp::min(self.min, id);
894894
self.max = cmp::max(self.max, id + 1);
895895
}
896+
896897
}
897898

898899

src/librustc/hir/map/mod.rs

+57-5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use hir::print as pprust;
3232

3333
use arena::TypedArena;
3434
use std::cell::RefCell;
35+
use std::cmp;
3536
use std::io;
3637
use std::mem;
3738

@@ -127,7 +128,10 @@ impl<'ast> MapEntry<'ast> {
127128
EntryStructCtor(id, _) => id,
128129
EntryLifetime(id, _) => id,
129130
EntryTyParam(id, _) => id,
130-
_ => return None
131+
132+
NotPresent |
133+
RootCrate |
134+
RootInlinedParent(_) => return None,
131135
})
132136
}
133137

@@ -196,6 +200,10 @@ pub struct Map<'ast> {
196200
map: RefCell<Vec<MapEntry<'ast>>>,
197201

198202
definitions: RefCell<Definitions>,
203+
204+
/// All NodeIds that are numerically greater or equal to this value come
205+
/// from inlined items.
206+
local_node_id_watermark: NodeId,
199207
}
200208

201209
impl<'ast> Map<'ast> {
@@ -550,6 +558,13 @@ impl<'ast> Map<'ast> {
550558
}
551559
}
552560

561+
pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem {
562+
match self.find_entry(id) {
563+
Some(RootInlinedParent(inlined_item)) => inlined_item,
564+
_ => bug!("expected inlined item, found {}", self.node_to_string(id)),
565+
}
566+
}
567+
553568
/// Returns the name associated with the given NodeId's AST.
554569
pub fn name(&self, id: NodeId) -> Name {
555570
match self.get(id) {
@@ -649,6 +664,10 @@ impl<'ast> Map<'ast> {
649664
pub fn node_to_user_string(&self, id: NodeId) -> String {
650665
node_id_to_string(self, id, false)
651666
}
667+
668+
pub fn is_inlined(&self, id: NodeId) -> bool {
669+
id >= self.local_node_id_watermark
670+
}
652671
}
653672

654673
pub struct NodesMatchingSuffix<'a, 'ast:'a> {
@@ -765,13 +784,37 @@ pub trait FoldOps {
765784
}
766785

767786
/// A Folder that updates IDs and Span's according to fold_ops.
768-
struct IdAndSpanUpdater<F> {
769-
fold_ops: F
787+
pub struct IdAndSpanUpdater<F> {
788+
fold_ops: F,
789+
min_id_assigned: NodeId,
790+
max_id_assigned: NodeId,
791+
}
792+
793+
impl<F: FoldOps> IdAndSpanUpdater<F> {
794+
pub fn new(fold_ops: F) -> IdAndSpanUpdater<F> {
795+
IdAndSpanUpdater {
796+
fold_ops: fold_ops,
797+
min_id_assigned: ::std::u32::MAX,
798+
max_id_assigned: ::std::u32::MIN,
799+
}
800+
}
801+
802+
pub fn id_range(&self) -> intravisit::IdRange {
803+
intravisit::IdRange {
804+
min: self.min_id_assigned,
805+
max: self.max_id_assigned + 1,
806+
}
807+
}
770808
}
771809

772810
impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
773811
fn new_id(&mut self, id: NodeId) -> NodeId {
774-
self.fold_ops.new_id(id)
812+
let id = self.fold_ops.new_id(id);
813+
814+
self.min_id_assigned = cmp::min(self.min_id_assigned, id);
815+
self.max_id_assigned = cmp::max(self.max_id_assigned, id);
816+
817+
id
775818
}
776819

777820
fn new_span(&mut self, span: Span) -> Span {
@@ -802,11 +845,14 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
802845
entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
803846
}
804847

848+
let local_node_id_watermark = map.len() as NodeId;
849+
805850
Map {
806851
forest: forest,
807852
dep_graph: forest.dep_graph.clone(),
808853
map: RefCell::new(map),
809854
definitions: RefCell::new(definitions),
855+
local_node_id_watermark: local_node_id_watermark
810856
}
811857
}
812858

@@ -818,7 +864,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
818864
ii: InlinedItem,
819865
fold_ops: F)
820866
-> &'ast InlinedItem {
821-
let mut fld = IdAndSpanUpdater { fold_ops: fold_ops };
867+
let mut fld = IdAndSpanUpdater::new(fold_ops);
822868
let ii = match ii {
823869
II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))),
824870
II::TraitItem(d, ti) => {
@@ -835,6 +881,12 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
835881
let ii = map.forest.inlined_items.alloc(ii);
836882
let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
837883

884+
// Assert that the ii_parent_id is the last NodeId in our reserved range
885+
assert!(ii_parent_id == fld.max_id_assigned);
886+
// Assert that we did not violate the invariant that all inlined HIR items
887+
// have NodeIds greater than or equal to `local_node_id_watermark`
888+
assert!(fld.min_id_assigned >= map.local_node_id_watermark);
889+
838890
let defs = &mut *map.definitions.borrow_mut();
839891
let mut def_collector = DefCollector::extend(ii_parent_id,
840892
parent_def_path.clone(),

src/librustc/middle/cstore.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,6 @@ pub struct ChildItem {
120120
pub vis: ty::Visibility,
121121
}
122122

123-
pub enum FoundAst<'ast> {
124-
Found(&'ast InlinedItem),
125-
FoundParent(DefId, &'ast hir::Item),
126-
NotFound,
127-
}
128-
129123
#[derive(Copy, Clone, Debug)]
130124
pub struct ExternCrate {
131125
/// def_id of an `extern crate` in the current crate that caused
@@ -250,7 +244,10 @@ pub trait CrateStore<'tcx> {
250244

251245
// misc. metadata
252246
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
253-
-> FoundAst<'tcx>;
247+
-> Option<(&'tcx InlinedItem, ast::NodeId)>;
248+
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>;
249+
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
250+
254251
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
255252
-> Option<Mir<'tcx>>;
256253
fn is_item_mir_available(&self, def: DefId) -> bool;
@@ -447,7 +444,16 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
447444

448445
// misc. metadata
449446
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
450-
-> FoundAst<'tcx> { bug!("maybe_get_item_ast") }
447+
-> Option<(&'tcx InlinedItem, ast::NodeId)> {
448+
bug!("maybe_get_item_ast")
449+
}
450+
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
451+
bug!("local_node_for_inlined_defid")
452+
}
453+
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
454+
bug!("defid_for_inlined_node")
455+
}
456+
451457
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
452458
-> Option<Mir<'tcx>> { bug!("maybe_get_item_mir") }
453459
fn is_item_mir_available(&self, def: DefId) -> bool {

src/librustc_const_eval/eval.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use self::EvalHint::*;
1717

1818
use rustc::hir::map as ast_map;
1919
use rustc::hir::map::blocks::FnLikeNode;
20-
use rustc::middle::cstore::{self, InlinedItem};
20+
use rustc::middle::cstore::InlinedItem;
2121
use rustc::traits;
2222
use rustc::hir::def::{Def, PathResolution};
2323
use rustc::hir::def_id::DefId;
@@ -142,13 +142,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
142142
}
143143
let mut used_substs = false;
144144
let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
145-
cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
145+
Some((&InlinedItem::Item(ref item), _)) => match item.node {
146146
hir::ItemConst(ref ty, ref const_expr) => {
147147
Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
148148
},
149149
_ => None
150150
},
151-
cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node {
151+
Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
152152
hir::ConstTraitItem(_, _) => {
153153
used_substs = true;
154154
if let Some(substs) = substs {
@@ -163,7 +163,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
163163
}
164164
_ => None
165165
},
166-
cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node {
166+
Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node {
167167
hir::ImplItemKind::Const(ref ty, ref expr) => {
168168
Some((&**expr, tcx.ast_ty_to_prim_ty(ty)))
169169
},
@@ -198,8 +198,8 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
198198
}
199199

200200
let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
201-
cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id),
202-
cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id),
201+
Some((&InlinedItem::Item(ref item), _)) => Some(item.id),
202+
Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
203203
_ => None
204204
};
205205
tcx.extern_const_fns.borrow_mut().insert(def_id,

src/librustc_metadata/astencode.rs

+42-9
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
8888
rbml_w.writer.seek(SeekFrom::Current(0)));
8989

9090
// Folding could be avoided with a smarter encoder.
91-
let ii = simplify_ast(ii);
91+
let (ii, expected_id_range) = simplify_ast(ii);
9292
let id_range = inlined_item_id_range(&ii);
93+
assert_eq!(expected_id_range, id_range);
9394

9495
rbml_w.start_tag(c::tag_ast as usize);
9596
id_range.encode(rbml_w);
@@ -186,6 +187,10 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
186187
pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId {
187188
// from_id_range should be non-empty
188189
assert!(!self.from_id_range.empty());
190+
// Make sure that translating the NodeId will actually yield a
191+
// meaningful result
192+
assert!(self.from_id_range.contains(id));
193+
189194
// Use wrapping arithmetic because otherwise it introduces control flow.
190195
// Maybe we should just have the control flow? -- aatch
191196
(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) {
279284
rbml_w.end_tag();
280285
}
281286

282-
struct NestedItemsDropper;
287+
struct NestedItemsDropper {
288+
id_range: IdRange
289+
}
283290

284291
impl Folder for NestedItemsDropper {
292+
293+
// The unit tests below run on HIR with NodeIds not properly assigned. That
294+
// causes an integer overflow. So we just don't track the id_range when
295+
// building the unit tests.
296+
#[cfg(not(test))]
297+
fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
298+
// Record the range of NodeIds we are visiting, so we can do a sanity
299+
// check later
300+
self.id_range.add(id);
301+
id
302+
}
303+
285304
fn fold_block(&mut self, blk: P<hir::Block>) -> P<hir::Block> {
286305
blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| {
287306
let stmts_sans_items = stmts.into_iter().filter_map(|stmt| {
@@ -322,10 +341,12 @@ impl Folder for NestedItemsDropper {
322341
// As it happens, trans relies on the fact that we do not export
323342
// nested items, as otherwise it would get confused when translating
324343
// inlined items.
325-
fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
326-
let mut fld = NestedItemsDropper;
344+
fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) {
345+
let mut fld = NestedItemsDropper {
346+
id_range: IdRange::max()
347+
};
327348

328-
match ii {
349+
let ii = match ii {
329350
// HACK we're not dropping items.
330351
InlinedItemRef::Item(i) => {
331352
InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld)))
@@ -339,7 +360,9 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
339360
InlinedItemRef::Foreign(i) => {
340361
InlinedItem::Foreign(P(fold::noop_fold_foreign_item(i.clone(), &mut fld)))
341362
}
342-
}
363+
};
364+
365+
(ii, fld.id_range)
343366
}
344367

345368
fn decode_ast(item_doc: rbml::Doc) -> InlinedItem {
@@ -361,8 +384,18 @@ impl tr for Def {
361384
match *self {
362385
Def::Fn(did) => Def::Fn(did.tr(dcx)),
363386
Def::Method(did) => Def::Method(did.tr(dcx)),
364-
Def::SelfTy(opt_did, impl_id) => { Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
365-
impl_id.map(|id| dcx.tr_id(id))) }
387+
Def::SelfTy(opt_did, impl_id) => {
388+
// Since the impl_id will never lie within the reserved range of
389+
// imported NodeIds, it does not make sense to translate it.
390+
// The result would not make any sense within the importing crate.
391+
// We also don't allow for impl items to be inlined (just their
392+
// members), so even if we had a DefId here, we wouldn't be able
393+
// to do much with it.
394+
// So, we set the id to DUMMY_NODE_ID. That way we make it
395+
// explicit that this is no usable NodeId.
396+
Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
397+
impl_id.map(|_| ast::DUMMY_NODE_ID))
398+
}
366399
Def::Mod(did) => { Def::Mod(did.tr(dcx)) }
367400
Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) }
368401
Def::Static(did, m) => { Def::Static(did.tr(dcx), m) }
@@ -1361,7 +1394,7 @@ fn test_simplification() {
13611394
with_testing_context(|lcx| {
13621395
let hir_item = lcx.lower_item(&item);
13631396
let item_in = InlinedItemRef::Item(&hir_item);
1364-
let item_out = simplify_ast(item_in);
1397+
let (item_out, _) = simplify_ast(item_in);
13651398
let item_exp = InlinedItem::Item(P(lcx.lower_item(&quote_item!(&cx,
13661399
fn new_int_alist<B>() -> alist<isize, B> {
13671400
return alist {eq_fn: eq_int, data: Vec::new()};

0 commit comments

Comments
 (0)