From 54c3299b3aed464b5c658c2dbfc1a270fb4c051f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 6 Jun 2021 13:48:00 +0200 Subject: [PATCH 01/17] Remove eval_always for HIR queries. They depend on `hir_crate` and `index_hir`. --- compiler/rustc_middle/src/hir/mod.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 5016c5ce95432..ded724c9badf7 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -163,7 +163,7 @@ pub fn provide(providers: &mut Providers) { let index = tcx.index_hir(()); index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) }; - providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id }; + providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.hir_crate(()).attrs, prefix: id }; providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9b0b1377875d1..7e9391b98f7ed 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -62,7 +62,6 @@ rustc_queries! { /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. query hir_owner(key: LocalDefId) -> Option> { - eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -71,7 +70,6 @@ rustc_queries! { /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. query hir_owner_parent(key: LocalDefId) -> hir::HirId { - eval_always desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -80,7 +78,6 @@ rustc_queries! { /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { - eval_always desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -89,7 +86,6 @@ rustc_queries! { /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. query hir_attrs(key: LocalDefId) -> rustc_middle::hir::AttributeMap<'tcx> { - eval_always desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -933,12 +929,6 @@ rustc_queries! { query def_span(def_id: DefId) -> Span { desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } - // FIXME(mw): DefSpans are not really inputs since they are derived from - // HIR. But at the moment HIR hashing still contains some hacks that allow - // to make type debuginfo to be source location independent. Declaring - // DefSpan an input makes sure that changes to these are always detected - // regardless of HIR hashing. - eval_always } query def_ident_span(def_id: DefId) -> Option { From f9e1de979db1e19acad5c2785057e0f2c25ee1f5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 19 Sep 2021 23:16:28 +0200 Subject: [PATCH 02/17] Stop referring to hir::Crate in hir_pretty. --- compiler/rustc_driver/src/pretty.rs | 30 ++++++++++++++++++---------- compiler/rustc_hir_pretty/src/lib.rs | 17 ++++++++-------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index 8e8bea9525dc9..2e9050dd672e1 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -59,23 +59,23 @@ where } fn call_with_pp_support_hir(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A where - F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate<'_>) -> A, + F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A, { match *ppmode { PpHirMode::Normal => { let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) }; - f(&annotation, tcx.hir().krate()) + f(&annotation, tcx.hir()) } PpHirMode::Identified => { let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) }; - f(&annotation, tcx.hir().krate()) + f(&annotation, tcx.hir()) } PpHirMode::Typed => { abort_on_err(tcx.analysis(()), tcx.sess); let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }; - tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().krate())) + tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir())) } } } @@ -443,17 +443,27 @@ pub fn print_after_hir_lowering<'tcx>( format!("{:#?}", krate) } - Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, krate| { + Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| { debug!("pretty printing HIR {:?}", s); let sess = annotation.sess(); let sm = sess.source_map(); - pprust_hir::print_crate(sm, krate, src_name, src, annotation.pp_ann()) + let attrs = |id| hir_map.attrs(id); + pprust_hir::print_crate( + sm, + hir_map.root_module(), + src_name, + src, + &attrs, + annotation.pp_ann(), + ) }), - HirTree => call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, krate| { - debug!("pretty printing HIR tree"); - format!("{:#?}", krate) - }), + HirTree => { + call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| { + debug!("pretty printing HIR tree"); + format!("{:#?}", hir_map.krate()) + }) + } _ => unreachable!(), }; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9196344cb3ffd..c1992b9b91bbf 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -15,7 +15,6 @@ use rustc_target::spec::abi::Abi; use std::borrow::Cow; use std::cell::Cell; -use std::collections::BTreeMap; use std::vec; pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: hir::HirId) -> String { @@ -69,7 +68,7 @@ impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { pub struct State<'a> { pub s: pp::Printer, comments: Option>, - attrs: &'a BTreeMap, + attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], ann: &'a (dyn PpAnn + 'a), } @@ -146,17 +145,18 @@ pub const INDENT_UNIT: usize = 4; /// it can scan the input text for comments to copy forward. pub fn print_crate<'a>( sm: &'a SourceMap, - krate: &hir::Crate<'_>, + krate: &hir::Mod<'_>, filename: FileName, input: String, + attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], ann: &'a dyn PpAnn, ) -> String { - let mut s = State::new_from_input(sm, filename, input, &krate.attrs, ann); + let mut s = State::new_from_input(sm, filename, input, attrs, ann); // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. - s.print_mod(&krate.module(), s.attrs(hir::CRATE_HIR_ID)); + s.print_mod(krate, (*attrs)(hir::CRATE_HIR_ID)); s.print_remaining_comments(); s.s.eof() } @@ -166,7 +166,7 @@ impl<'a> State<'a> { sm: &'a SourceMap, filename: FileName, input: String, - attrs: &'a BTreeMap, + attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], ann: &'a dyn PpAnn, ) -> State<'a> { State { @@ -178,7 +178,7 @@ impl<'a> State<'a> { } fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] { - self.attrs.get(&id).map_or(&[], |la| *la) + (self.attrs)(id) } } @@ -186,8 +186,7 @@ pub fn to_string(ann: &dyn PpAnn, f: F) -> String where F: FnOnce(&mut State<'_>), { - let mut printer = - State { s: pp::mk_printer(), comments: None, attrs: &BTreeMap::default(), ann }; + let mut printer = State { s: pp::mk_printer(), comments: None, attrs: &|_| &[], ann }; f(&mut printer); printer.s.eof() } From 48a339ddbbc1e1c364d1cb39d3fef8aad9105345 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 16 Jul 2021 14:42:26 +0200 Subject: [PATCH 03/17] Store lowering outputs per owner. --- Cargo.lock | 1 + compiler/rustc_ast_lowering/src/expr.rs | 5 +- compiler/rustc_ast_lowering/src/item.rs | 21 +++-- compiler/rustc_ast_lowering/src/lib.rs | 92 ++++++++++++------- compiler/rustc_hir/src/hir.rs | 39 +++++--- compiler/rustc_middle/Cargo.toml | 1 + .../rustc_middle/src/hir/map/collector.rs | 16 ++-- compiler/rustc_middle/src/hir/map/mod.rs | 54 ++++++++--- compiler/rustc_middle/src/hir/mod.rs | 46 ++-------- compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/ty/context.rs | 3 +- compiler/rustc_resolve/src/late.rs | 6 +- compiler/rustc_resolve/src/lib.rs | 8 +- 13 files changed, 169 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 197b2c8f3f06a..00d470017bb7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4088,6 +4088,7 @@ dependencies = [ "polonius-engine", "rand 0.8.4", "rand_xoshiro 0.6.0", + "rustc-rayon", "rustc-rayon-core", "rustc_apfloat", "rustc_arena", diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6027027428eee..22f93f5078817 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -252,9 +252,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } // Merge attributes into the inner expression. if !e.attrs.is_empty() { - let old_attrs = self.attrs.get(&ex.hir_id).map(|la| *la).unwrap_or(&[]); + let old_attrs = + self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]); self.attrs.insert( - ex.hir_id, + ex.hir_id.local_id, &*self.arena.alloc_from_iter( e.attrs .iter() diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ea9eb0cf2742b..c6572b19d1d1d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -10,6 +10,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; +use rustc_index::vec::Idx; use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -99,11 +100,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> T { let old_len = self.in_scope_lifetimes.len(); - let parent_generics = match self.owners[parent_hir_id].unwrap().expect_item().kind { - hir::ItemKind::Impl(hir::Impl { ref generics, .. }) - | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, - _ => &[], - }; + let parent_generics = + match self.owners[parent_hir_id].as_ref().unwrap().node.expect_item().kind { + hir::ItemKind::Impl(hir::Impl { ref generics, .. }) + | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, + _ => &[], + }; let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind { hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()), _ => None, @@ -493,7 +495,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = hir::ItemKind::Use(path, hir::UseKind::Single); let vis = this.rebuild_vis(&vis); if let Some(attrs) = attrs { - this.attrs.insert(hir::HirId::make_owner(new_id), attrs); + this.attrs.insert(hir::ItemLocalId::new(0), attrs); } let item = hir::Item { @@ -568,7 +570,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs); if let Some(attrs) = attrs { - this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs); + this.attrs.insert(hir::ItemLocalId::new(0), attrs); } let item = hir::Item { @@ -971,7 +973,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::BodyId { let body = hir::Body { generator_kind: self.generator_kind, params, value }; let id = body.id(); - self.bodies.insert(id, body); + debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); + self.bodies.insert(id.hir_id.local_id, body); id } @@ -1124,7 +1127,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // If this is the simple case, this parameter will end up being the same as the // original parameter, but with a different pattern id. - let stmt_attrs = this.attrs.get(¶meter.hir_id).copied(); + let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied(); let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident); let new_parameter = hir::Param { hir_id: parameter.hir_id, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 245199e375113..1b82ac68e159d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -35,14 +35,13 @@ #![feature(iter_zip)] #![recursion_limit = "256"] -use rustc_ast::node_id::NodeMap; use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree}; use rustc_ast::visit; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -97,13 +96,12 @@ struct LoweringContext<'a, 'hir: 'a> { arena: &'hir Arena<'hir>, /// The items being lowered are collected here. - owners: IndexVec>>, - bodies: BTreeMap>, + owners: IndexVec>>, + bodies: BTreeMap>, + attrs: BTreeMap, generator_kind: Option, - attrs: BTreeMap, - /// When inside an `async` context, this is the `HirId` of the /// `task_context` local bound to the resume argument of the generator. task_context: Option, @@ -152,6 +150,9 @@ struct LoweringContext<'a, 'hir: 'a> { item_local_id_counter: hir::ItemLocalId, node_id_to_hir_id: IndexVec>, + /// NodeIds that are lowered inside the current HIR owner. + local_node_ids: Vec, + allow_try_trait: Option>, allow_gen_future: Option>, } @@ -182,7 +183,7 @@ pub trait ResolverAstLowering { fn next_node_id(&mut self) -> NodeId; - fn take_trait_map(&mut self) -> NodeMap>; + fn take_trait_map(&mut self, node: NodeId) -> Option>; fn opt_local_def_id(&self, node: NodeId) -> Option; @@ -314,12 +315,13 @@ pub fn lower_crate<'a, 'hir>( ) -> &'hir hir::Crate<'hir> { let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); + let owners = IndexVec::from_fn_n(|_| None, resolver.definitions().def_index_count()); LoweringContext { sess, resolver, nt_to_tokenstream, arena, - owners: IndexVec::default(), + owners, bodies: BTreeMap::new(), attrs: BTreeMap::default(), catch_scope: None, @@ -331,6 +333,7 @@ pub fn lower_crate<'a, 'hir>( current_hir_id_owner: CRATE_DEF_ID, item_local_id_counter: hir::ItemLocalId::new(0), node_id_to_hir_id: IndexVec::new(), + local_node_ids: Vec::new(), generator_kind: None, task_context: None, current_item: None, @@ -420,14 +423,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::OwnerNode::Crate(lctx.arena.alloc(module)) }); - let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (k, v) in self.resolver.take_trait_map().into_iter() { - if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) { - let map = trait_map.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, v.into_boxed_slice()); - } - } - let mut def_id_to_hir_id = IndexVec::default(); for (node_id, hir_id) in self.node_id_to_hir_id.into_iter_enumerated() { @@ -441,16 +436,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id); - #[cfg(debug_assertions)] - for (&id, attrs) in self.attrs.iter() { - // Verify that we do not store empty slices in the map. - if attrs.is_empty() { - panic!("Stored empty attributes for {:?}", id); - } - } - - let krate = - hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs }; + let krate = hir::Crate { owners: self.owners }; self.arena.alloc(krate) } @@ -468,25 +454,57 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> LocalDefId { let def_id = self.resolver.local_def_id(owner); - // Always allocate the first `HirId` for the owner itself. - let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id)); - debug_assert_eq!(_old, None); - + let current_attrs = std::mem::take(&mut self.attrs); + let current_bodies = std::mem::take(&mut self.bodies); + let current_node_ids = std::mem::take(&mut self.local_node_ids); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id); let current_local_counter = std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); + // Always allocate the first `HirId` for the owner itself. + let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id)); + debug_assert_eq!(_old, None); + self.local_node_ids.push(owner); + let item = f(self); + let info = self.make_owner_info(item); + self.attrs = current_attrs; + self.bodies = current_bodies; + self.local_node_ids = current_node_ids; self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; - let _old = self.owners.insert(def_id, item); + let _old = self.owners.insert(def_id, info); debug_assert!(_old.is_none()); def_id } + fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> { + let attrs = std::mem::take(&mut self.attrs); + let bodies = std::mem::take(&mut self.bodies); + let local_node_ids = std::mem::take(&mut self.local_node_ids); + let trait_map = local_node_ids + .into_iter() + .filter_map(|node_id| { + let hir_id = self.node_id_to_hir_id[node_id]?; + let traits = self.resolver.take_trait_map(node_id)?; + Some((hir_id.local_id, traits.into_boxed_slice())) + }) + .collect(); + + #[cfg(debug_assertions)] + for (&id, attrs) in attrs.iter() { + // Verify that we do not store empty slices in the map. + if attrs.is_empty() { + panic!("Stored empty attributes for {:?}", id); + } + } + + hir::OwnerInfo { node, attrs, bodies, trait_map } + } + /// This method allocates a new `HirId` for the given `NodeId` and stores it in /// the `LoweringContext`'s `NodeId => HirId` map. /// Take care not to call this method if the resulting `HirId` is then not @@ -501,6 +519,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let owner = self.current_hir_id_owner; let local_id = self.item_local_id_counter; self.item_local_id_counter.increment_by(1); + self.local_node_ids.push(ast_node_id); hir::HirId { owner, local_id } }) } @@ -791,9 +810,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if attrs.is_empty() { None } else { + debug_assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))); debug_assert!(!ret.is_empty()); - self.attrs.insert(id, ret); + self.attrs.insert(id.local_id, ret); Some(ret) } } @@ -819,9 +839,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) { - if let Some(&a) = self.attrs.get(&target_id) { + debug_assert_eq!(id.owner, self.current_hir_id_owner); + debug_assert_eq!(target_id.owner, self.current_hir_id_owner); + if let Some(&a) = self.attrs.get(&target_id.local_id) { debug_assert!(!a.is_empty()); - self.attrs.insert(id, a); + self.attrs.insert(id.local_id, a); } } @@ -2066,7 +2088,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let hir_id = self.next_id(); if let Some(a) = attrs { debug_assert!(!a.is_empty()); - self.attrs.insert(hir_id, a); + self.attrs.insert(hir_id.local_id, a); } let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None }; self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local))) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index fdd52bd74952f..a24d92d0c01b7 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -662,6 +662,16 @@ pub struct WhereEqPredicate<'hir> { pub rhs_ty: &'hir Ty<'hir>, } +#[derive(Debug)] +pub struct OwnerInfo<'hir> { + pub node: OwnerNode<'hir>, + pub attrs: BTreeMap, + pub bodies: BTreeMap>, + /// Map indicating what traits are in scope for places where this + /// is relevant; generated by resolve. + pub trait_map: FxHashMap>, +} + /// The top-level data structure that stores the entire contents of /// the crate currently being compiled. /// @@ -670,40 +680,39 @@ pub struct WhereEqPredicate<'hir> { /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #[derive(Debug)] pub struct Crate<'hir> { - pub owners: IndexVec>>, - pub bodies: BTreeMap>, - - /// Map indicating what traits are in scope for places where this - /// is relevant; generated by resolve. - pub trait_map: FxHashMap>>, - - /// Collected attributes from HIR nodes. - pub attrs: BTreeMap, + pub owners: IndexVec>>, } impl Crate<'hir> { pub fn module(&self) -> &'hir Mod<'hir> { - if let Some(OwnerNode::Crate(m)) = self.owners[CRATE_DEF_ID] { m } else { panic!() } + let i = self.owners[CRATE_DEF_ID].as_ref().unwrap().node; + if let OwnerNode::Crate(m) = i { m } else { panic!() } } pub fn item(&self, id: ItemId) -> &'hir Item<'hir> { - self.owners[id.def_id].as_ref().unwrap().expect_item() + self.owners[id.def_id].as_ref().unwrap().node.expect_item() } pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().expect_trait_item() + self.owners[id.def_id].as_ref().unwrap().node.expect_trait_item() } pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().expect_impl_item() + self.owners[id.def_id].as_ref().unwrap().node.expect_impl_item() } pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().expect_foreign_item() + self.owners[id.def_id].as_ref().unwrap().node.expect_foreign_item() } pub fn body(&self, id: BodyId) -> &Body<'hir> { - &self.bodies[&id] + let HirId { owner, local_id } = id.hir_id; + &self.owners[owner].as_ref().unwrap().bodies[&local_id] + } + + pub fn attrs(&self, id: HirId) -> &'hir [Attribute] { + let HirId { owner, local_id } = id; + &self.owners[owner].as_ref().unwrap().attrs.get(&local_id).map(|la| *la).unwrap_or(&[]) } } diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index d06c593d39481..daeccde6024e6 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -12,6 +12,7 @@ bitflags = "1.2.1" either = "1.5.0" gsgdt = "0.1.2" tracing = "0.1" +rustc-rayon = "0.3.1" rustc-rayon-core = "0.3.1" polonius-engine = "0.13.0" rustc_apfloat = { path = "../rustc_apfloat" } diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index efebf73224f27..1e405d0d7fc12 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -86,12 +86,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { collector } - pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> { - // Insert bodies into the map - for (id, body) in self.krate.bodies.iter() { - let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies; - assert!(bodies.insert(id.hir_id.local_id, body).is_none()); - } + pub(super) fn finalize_and_compute_crate_hash(self) -> IndexedHir<'hir> { IndexedHir { map: self.map, parenting: self.parenting } } @@ -101,9 +96,14 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { let mut nodes = IndexVec::new(); nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() })); + let mut bodies = FxHashMap::default(); + for (id, body) in self.krate.owners[owner].as_ref().unwrap().bodies.iter() { + let _old = bodies.insert(*id, body); + debug_assert!(_old.is_none()); + } + debug_assert!(self.map[owner].is_none()); - self.map[owner] = - Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() })); + self.map[owner] = Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies })); } fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index e6f56b0be9303..9a1bdba824e1d 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,6 +1,6 @@ use self::collector::NodeCollector; -use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner}; +use crate::hir::{IndexedHir, ModuleItems, Owner}; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; @@ -166,8 +166,8 @@ impl<'hir> Map<'hir> { pub fn items(&self) -> impl Iterator> + 'hir { let krate = self.krate(); - krate.owners.iter().filter_map(|owner| match owner.as_ref()? { - OwnerNode::Item(item) => Some(*item), + krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node { + OwnerNode::Item(item) => Some(item), _ => None, }) } @@ -495,11 +495,35 @@ impl<'hir> Map<'hir> { /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir().krate().body_ids.iter()`. pub fn body_owners(self) -> impl Iterator + 'hir { - self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id)) + self.krate() + .owners + .iter_enumerated() + .flat_map(move |(owner, owner_info)| { + let bodies = &owner_info.as_ref()?.bodies; + Some(bodies.keys().map(move |&local_id| { + let hir_id = HirId { owner, local_id }; + let body_id = BodyId { hir_id }; + self.body_owner_def_id(body_id) + })) + }) + .flatten() } pub fn par_body_owners(self, f: F) { - par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id))); + use rustc_data_structures::sync::{par_iter, ParallelIterator}; + #[cfg(parallel_compiler)] + use rustc_rayon::iter::IndexedParallelIterator; + + par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| { + let owner = LocalDefId::new(owner); + if let Some(owner_info) = owner_info { + par_iter(&owner_info.bodies).for_each(|(&local_id, _)| { + let hir_id = HirId { owner, local_id }; + let body_id = BodyId { hir_id }; + f(self.body_owner_def_id(body_id)) + }) + } + }); } pub fn ty_param_owner(&self, id: HirId) -> HirId { @@ -551,9 +575,14 @@ impl<'hir> Map<'hir> { /// Walks the attributes in a crate. pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) { let krate = self.krate(); - for (&id, attrs) in krate.attrs.iter() { - for a in *attrs { - visitor.visit_attribute(id, a) + for (owner, info) in krate.owners.iter_enumerated() { + if let Some(info) = info { + for (&local_id, attrs) in info.attrs.iter() { + let id = HirId { owner, local_id }; + for a in *attrs { + visitor.visit_attribute(id, a) + } + } } } } @@ -572,7 +601,7 @@ impl<'hir> Map<'hir> { { let krate = self.krate(); for owner in krate.owners.iter().filter_map(Option::as_ref) { - match owner { + match owner.node { OwnerNode::Item(item) => visitor.visit_item(item), OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), @@ -588,7 +617,7 @@ impl<'hir> Map<'hir> { V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, { let krate = self.krate(); - par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() { + par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref().map(|o| o.node) { Some(OwnerNode::Item(item)) => visitor.visit_item(item), Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), @@ -1091,7 +1120,10 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() { def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher); fingerprint.hash_stable(&mut hcx, &mut stable_hasher); - AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id } + tcx.untracked_crate.owners[*def_id] + .as_ref() + .unwrap() + .attrs .hash_stable(&mut hcx, &mut stable_hasher); if tcx.sess.opts.debugging_opts.incremental_relative_spans { let span = tcx.untracked_resolutions.definitions.def_span(*def_id); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index ded724c9badf7..9f2ee9f341c3c 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -77,47 +77,21 @@ impl<'a, 'tcx> HashStable> for OwnerNodes<'tcx> { } } -/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted -/// to the nodes whose `HirId::owner` is `prefix`. -#[derive(Copy, Clone)] +/// Attributes owner by a HIR owner. +#[derive(Copy, Clone, Debug, HashStable)] pub struct AttributeMap<'tcx> { - map: &'tcx BTreeMap, - prefix: LocalDefId, -} - -impl<'a, 'tcx> HashStable> for AttributeMap<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let range = self.range(); - - range.clone().count().hash_stable(hcx, hasher); - for (key, value) in range { - key.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - } - } -} - -impl<'tcx> std::fmt::Debug for AttributeMap<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("AttributeMap") - .field("prefix", &self.prefix) - .field("range", &&self.range().collect::>()[..]) - .finish() - } + map: &'tcx BTreeMap, } impl<'tcx> AttributeMap<'tcx> { - fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { - self.map.get(&HirId { owner: self.prefix, local_id: id }).copied().unwrap_or(&[]) + fn new(owner_info: &'tcx Option>) -> AttributeMap<'tcx> { + const FALLBACK: &'static BTreeMap = &BTreeMap::new(); + let map = owner_info.as_ref().map_or(FALLBACK, |info| &info.attrs); + AttributeMap { map } } - fn range(&self) -> std::collections::btree_map::Range<'_, rustc_hir::HirId, &[Attribute]> { - let local_zero = ItemLocalId::from_u32(0); - let range = HirId { owner: self.prefix, local_id: local_zero }..HirId { - owner: LocalDefId { local_def_index: self.prefix.local_def_index + 1 }, - local_id: local_zero, - }; - self.map.range(range) + fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { + self.map.get(&id).copied().unwrap_or(&[]) } } @@ -163,7 +137,7 @@ pub fn provide(providers: &mut Providers) { let index = tcx.index_hir(()); index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) }; - providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.hir_crate(()).attrs, prefix: id }; + providers.hir_attrs = |tcx, id| AttributeMap::new(&tcx.hir_crate(()).owners[id]); providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e41f5add457fb..e7219cc58a18a 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,6 +30,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(core_intrinsics)] +#![feature(const_btree_new)] #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6a6fb30dce837..cbbd89e903335 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2828,7 +2828,8 @@ fn ptr_eq(t: *const T, u: *const U) -> bool { } pub fn provide(providers: &mut ty::query::Providers) { - providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id); + providers.in_scope_traits_map = + |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map); providers.resolutions = |tcx, ()| &tcx.untracked_resolutions; providers.module_exports = |tcx, id| tcx.resolutions(()).export_map.get(&id).map(|v| &v[..]); providers.crate_name = |tcx, id| { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 9563325796538..0a24e00ee4bf5 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1994,7 +1994,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if ns == ValueNS { let item_name = path.last().unwrap().ident; let traits = self.traits_in_scope(item_name, ns); - self.r.trait_map.as_mut().unwrap().insert(id, traits); + self.r.trait_map.insert(id, traits); } if PrimTy::from_name(path[0].ident.name).is_some() { @@ -2479,12 +2479,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // the field name so that we can do some nice error reporting // later on in typeck. let traits = self.traits_in_scope(ident, ValueNS); - self.r.trait_map.as_mut().unwrap().insert(expr.id, traits); + self.r.trait_map.insert(expr.id, traits); } ExprKind::MethodCall(ref segment, ..) => { debug!("(recording candidate traits for expr) recording traits for {}", expr.id); let traits = self.traits_in_scope(segment.ident, ValueNS); - self.r.trait_map.as_mut().unwrap().insert(expr.id, traits); + self.r.trait_map.insert(expr.id, traits); } _ => { // Nothing to do. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3e7783033efa5..28fe365fb584b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -930,7 +930,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap, export_map: ExportMap, - trait_map: Option>>, + trait_map: NodeMap>, /// A map from nodes to anonymous modules. /// Anonymous modules are pseudo-modules that are implicitly created around items @@ -1185,8 +1185,8 @@ impl ResolverAstLowering for Resolver<'_> { self.next_node_id() } - fn take_trait_map(&mut self) -> NodeMap> { - std::mem::replace(&mut self.trait_map, None).unwrap() + fn take_trait_map(&mut self, node: NodeId) -> Option> { + self.trait_map.remove(&node) } fn opt_local_def_id(&self, node: NodeId) -> Option { @@ -1363,7 +1363,7 @@ impl<'a> Resolver<'a> { label_res_map: Default::default(), extern_crate_map: Default::default(), export_map: FxHashMap::default(), - trait_map: Some(NodeMap::default()), + trait_map: NodeMap::default(), underscore_disambiguator: 0, empty_module, module_map, From cd1ace488fc328ee20397783e3046971e6f09ac5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 17 Sep 2021 19:41:05 +0200 Subject: [PATCH 04/17] Use an IndexVec for bodies. --- compiler/rustc_ast_lowering/src/item.rs | 3 ++- compiler/rustc_ast_lowering/src/lib.rs | 4 ++-- compiler/rustc_hir/src/arena.rs | 1 + compiler/rustc_hir/src/hir.rs | 6 +++--- .../rustc_middle/src/hir/map/collector.rs | 6 +----- compiler/rustc_middle/src/hir/map/mod.rs | 20 ++++++++++++------- compiler/rustc_middle/src/hir/mod.rs | 2 +- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c6572b19d1d1d..cac5bb56c9f5f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -974,7 +974,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let body = hir::Body { generator_kind: self.generator_kind, params, value }; let id = body.id(); debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); - self.bodies.insert(id.hir_id.local_id, body); + self.bodies.ensure_contains_elem(id.hir_id.local_id, || None); + self.bodies[id.hir_id.local_id] = Some(self.arena.alloc(body)); id } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1b82ac68e159d..8375a37d32a48 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -97,7 +97,7 @@ struct LoweringContext<'a, 'hir: 'a> { /// The items being lowered are collected here. owners: IndexVec>>, - bodies: BTreeMap>, + bodies: IndexVec>>, attrs: BTreeMap, generator_kind: Option, @@ -322,7 +322,7 @@ pub fn lower_crate<'a, 'hir>( nt_to_tokenstream, arena, owners, - bodies: BTreeMap::new(), + bodies: IndexVec::new(), attrs: BTreeMap::default(), catch_scope: None, loop_scope: None, diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index f07e52e04daa9..5334f6d729dc5 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -19,6 +19,7 @@ macro_rules! arena_types { [] attribute: rustc_ast::Attribute, [] block: rustc_hir::Block<$tcx>, [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>, + [] body: rustc_hir::Body<$tcx>, [] generic_arg: rustc_hir::GenericArg<$tcx>, [] generic_args: rustc_hir::GenericArgs<$tcx>, [] generic_bound: rustc_hir::GenericBound<$tcx>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a24d92d0c01b7..1d1c0a0de13d8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -666,7 +666,7 @@ pub struct WhereEqPredicate<'hir> { pub struct OwnerInfo<'hir> { pub node: OwnerNode<'hir>, pub attrs: BTreeMap, - pub bodies: BTreeMap>, + pub bodies: IndexVec>>, /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. pub trait_map: FxHashMap>, @@ -705,9 +705,9 @@ impl Crate<'hir> { self.owners[id.def_id].as_ref().unwrap().node.expect_foreign_item() } - pub fn body(&self, id: BodyId) -> &Body<'hir> { + pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { let HirId { owner, local_id } = id.hir_id; - &self.owners[owner].as_ref().unwrap().bodies[&local_id] + self.owners[owner].as_ref().unwrap().bodies[local_id].unwrap() } pub fn attrs(&self, id: HirId) -> &'hir [Attribute] { diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 1e405d0d7fc12..868c1b7853e5e 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -96,11 +96,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { let mut nodes = IndexVec::new(); nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() })); - let mut bodies = FxHashMap::default(); - for (id, body) in self.krate.owners[owner].as_ref().unwrap().bodies.iter() { - let _old = bodies.insert(*id, body); - debug_assert!(_old.is_none()); - } + let bodies = &self.krate.owners[owner].as_ref().unwrap().bodies; debug_assert!(self.map[owner].is_none()); self.map[owner] = Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies })); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 9a1bdba824e1d..66d4ec2eeb6da 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -381,7 +381,7 @@ impl<'hir> Map<'hir> { } pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { - self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap() + self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[id.hir_id.local_id].unwrap() } pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { @@ -500,10 +500,13 @@ impl<'hir> Map<'hir> { .iter_enumerated() .flat_map(move |(owner, owner_info)| { let bodies = &owner_info.as_ref()?.bodies; - Some(bodies.keys().map(move |&local_id| { + Some(bodies.iter_enumerated().filter_map(move |(local_id, body)| { + if body.is_none() { + return None; + } let hir_id = HirId { owner, local_id }; let body_id = BodyId { hir_id }; - self.body_owner_def_id(body_id) + Some(self.body_owner_def_id(body_id)) })) }) .flatten() @@ -517,10 +520,13 @@ impl<'hir> Map<'hir> { par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| { let owner = LocalDefId::new(owner); if let Some(owner_info) = owner_info { - par_iter(&owner_info.bodies).for_each(|(&local_id, _)| { - let hir_id = HirId { owner, local_id }; - let body_id = BodyId { hir_id }; - f(self.body_owner_def_id(body_id)) + par_iter(&owner_info.bodies.raw).enumerate().for_each(|(local_id, body)| { + if body.is_some() { + let local_id = ItemLocalId::new(local_id); + let hir_id = HirId { owner, local_id }; + let body_id = BodyId { hir_id }; + f(self.body_owner_def_id(body_id)) + } }) } }); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 9f2ee9f341c3c..094198713cc21 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -65,7 +65,7 @@ pub struct OwnerNodes<'tcx> { // The zeroth node's parent is trash, but is never accessed. nodes: IndexVec>>, /// Content of local bodies. - bodies: FxHashMap>, + bodies: &'tcx IndexVec>>, } impl<'a, 'tcx> HashStable> for OwnerNodes<'tcx> { From 457de0848777473ddafda998ab9384cbfbf4b87a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 19 Sep 2021 22:17:50 +0200 Subject: [PATCH 05/17] Forbid hashing HIR outside of indexing. --- Cargo.lock | 2 + compiler/rustc_ast_lowering/Cargo.toml | 1 + compiler/rustc_ast_lowering/src/lib.rs | 45 ++----------- .../rustc_middle/src/hir/map/collector.rs | 22 ++++--- compiler/rustc_middle/src/hir/map/mod.rs | 8 +-- compiler/rustc_middle/src/hir/mod.rs | 13 ++-- compiler/rustc_middle/src/ty/context.rs | 7 +- compiler/rustc_query_system/src/ich/hcx.rs | 64 +++++++++++-------- .../rustc_query_system/src/ich/impls_hir.rs | 10 ++- compiler/rustc_resolve/Cargo.toml | 1 + compiler/rustc_resolve/src/lib.rs | 45 ++----------- 11 files changed, 86 insertions(+), 132 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00d470017bb7f..0d89ffb726435 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3552,6 +3552,7 @@ dependencies = [ "rustc_errors", "rustc_hir", "rustc_index", + "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", @@ -4333,6 +4334,7 @@ dependencies = [ "rustc_index", "rustc_metadata", "rustc_middle", + "rustc_query_system", "rustc_session", "rustc_span", "smallvec", diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index f4859ee4ae91f..7989af24d9986 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -14,6 +14,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } +rustc_query_system = { path = "../rustc_query_system" } rustc_span = { path = "../rustc_span" } rustc_errors = { path = "../rustc_errors" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8375a37d32a48..80b95b99b165e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -51,13 +51,14 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::ExpnId; -use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind}; +use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -179,6 +180,8 @@ pub trait ResolverAstLowering { /// This should only return `None` during testing. fn definitions(&mut self) -> &mut Definitions; + fn create_stable_hashing_context(&self) -> StableHashingContext<'_>; + fn lint_buffer(&mut self) -> &mut LintBuffer; fn next_node_id(&mut self) -> NodeId; @@ -201,37 +204,6 @@ pub trait ResolverAstLowering { ) -> LocalDefId; } -struct LoweringHasher<'a> { - source_map: CachingSourceMapView<'a>, - resolver: &'a dyn ResolverAstLowering, -} - -impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> { - #[inline] - fn hash_spans(&self) -> bool { - true - } - - #[inline] - fn def_span(&self, id: LocalDefId) -> Span { - self.resolver.def_span(id) - } - - #[inline] - fn def_path_hash(&self, def_id: DefId) -> DefPathHash { - self.resolver.def_path_hash(def_id) - } - - #[inline] - fn span_data_to_lines_and_cols( - &mut self, - span: &rustc_span::SpanData, - ) -> Option<(Lrc, usize, rustc_span::BytePos, usize, rustc_span::BytePos)> - { - self.source_map.span_data_to_lines_and_cols(span) - } -} - /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, /// and if so, what meaning it has. #[derive(Debug)] @@ -440,13 +412,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(krate) } - fn create_stable_hashing_context(&self) -> LoweringHasher<'_> { - LoweringHasher { - source_map: CachingSourceMapView::new(self.sess.source_map()), - resolver: self.resolver, - } - } - fn with_hir_id_owner( &mut self, owner: NodeId, @@ -566,7 +531,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { allow_internal_unstable, reason, self.sess.edition(), - self.create_stable_hashing_context(), + self.resolver.create_stable_hashing_context(), ) } diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 868c1b7853e5e..80e48a4f74b4f 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -51,18 +51,21 @@ fn insert_vec_map(map: &mut IndexVec>, k: K, v: V map[k] = Some(v); } -fn hash_body( - hcx: &mut StableHashingContext<'_>, +fn hash_body<'s, 'hir: 's>( + hcx: &mut StableHashingContext<'s>, item_like: impl for<'a> HashStable>, + hash_bodies: bool, + owner: LocalDefId, + bodies: &'hir IndexVec>>, ) -> Fingerprint { let mut stable_hasher = StableHasher::new(); - hcx.while_hashing_hir_bodies(true, |hcx| { - item_like.hash_stable(hcx, &mut stable_hasher); + hcx.with_hir_bodies(hash_bodies, owner, bodies, |hcx| { + item_like.hash_stable(hcx, &mut stable_hasher) }); stable_hasher.finish() } -impl<'a, 'hir> NodeCollector<'a, 'hir> { +impl<'a, 'hir: 'a> NodeCollector<'a, 'hir> { pub(super) fn root( sess: &'a Session, arena: &'hir Arena<'hir>, @@ -91,15 +94,16 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) { - let hash = hash_body(&mut self.hcx, node); - let mut nodes = IndexVec::new(); nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() })); let bodies = &self.krate.owners[owner].as_ref().unwrap().bodies; + let hash = hash_body(&mut self.hcx, node, true, owner, bodies); + let node_hash = hash_body(&mut self.hcx, node, false, owner, bodies); + debug_assert!(self.map[owner].is_none()); - self.map[owner] = Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies })); + self.map[owner] = Some(self.arena.alloc(OwnerNodes { hash, node_hash, nodes, bodies })); } fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { @@ -176,7 +180,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } } -impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { +impl<'a, 'hir: 'a> Visitor<'hir> for NodeCollector<'a, 'hir> { type Map = Map<'hir>; /// Because we want to track parent items and so forth, enable diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 66d4ec2eeb6da..8c11fd8a280fc 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -874,21 +874,21 @@ impl<'hir> Map<'hir> { pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::Item(item) }) => item, + Some(Owner { node: OwnerNode::Item(item), .. }) => item, _ => bug!("expected item, found {}", self.node_to_string(id)), } } pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::ImplItem(item) }) => item, + Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item, _ => bug!("expected impl item, found {}", self.node_to_string(id)), } } pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::TraitItem(item) }) => item, + Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item, _ => bug!("expected trait item, found {}", self.node_to_string(id)), } } @@ -902,7 +902,7 @@ impl<'hir> Map<'hir> { pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::ForeignItem(item) }) => item, + Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item, _ => bug!("expected foreign item, found {}", self.node_to_string(id)), } } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 094198713cc21..6d24190eefb5c 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -39,12 +39,14 @@ pub struct IndexedHir<'hir> { #[derive(Copy, Clone, Debug)] pub struct Owner<'tcx> { node: OwnerNode<'tcx>, + node_hash: Fingerprint, } impl<'a, 'tcx> HashStable> for Owner<'tcx> { + #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Owner { node } = self; - hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher)); + let Owner { node: _, node_hash } = self; + node_hash.hash_stable(hcx, hasher) } } @@ -61,6 +63,8 @@ pub struct ParentedNode<'tcx> { pub struct OwnerNodes<'tcx> { /// Pre-computed hash of the full HIR. hash: Fingerprint, + /// Pre-computed hash of the top node. + node_hash: Fingerprint, /// Full HIR for the current owner. // The zeroth node's parent is trash, but is never accessed. nodes: IndexVec>>, @@ -69,10 +73,11 @@ pub struct OwnerNodes<'tcx> { } impl<'a, 'tcx> HashStable> for OwnerNodes<'tcx> { + #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // We ignore the `nodes` and `bodies` fields since these refer to information included in // `hash` which is hashed in the collector and used for the crate hash. - let OwnerNodes { hash, nodes: _, bodies: _ } = *self; + let OwnerNodes { hash, node_hash: _, nodes: _, bodies: _ } = *self; hash.hash_stable(hcx, hasher); } } @@ -130,7 +135,7 @@ pub fn provide(providers: &mut Providers) { let owner = tcx.index_hir(()).map[id].as_ref()?; let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. - Some(Owner { node }) + Some(Owner { node, node_hash: owner.node_hash }) }; providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref(); providers.hir_owner_parent = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index cbbd89e903335..5dea574c48417 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1342,20 +1342,15 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.untracked_crate; let resolutions = &self.gcx.untracked_resolutions; - - StableHashingContext::new(self.sess, krate, &resolutions.definitions, &*resolutions.cstore) + StableHashingContext::new(self.sess, &resolutions.definitions, &*resolutions.cstore) } #[inline(always)] pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.untracked_crate; let resolutions = &self.gcx.untracked_resolutions; - StableHashingContext::ignore_spans( self.sess, - krate, &resolutions.definitions, &*resolutions.cstore, ) diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index f2e935c59fce2..cfef2073373cc 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -6,6 +6,7 @@ use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::definitions::{DefPathHash, Definitions}; +use rustc_index::vec::IndexVec; use rustc_session::cstore::CrateStore; use rustc_session::Session; use rustc_span::source_map::SourceMap; @@ -27,7 +28,6 @@ pub struct StableHashingContext<'a> { cstore: &'a dyn CrateStore, pub(super) body_resolver: BodyResolver<'a>, hash_spans: bool, - hash_bodies: bool, pub(super) node_id_hashing_mode: NodeIdHashingMode, // Very often, we are hashing something that does not need the @@ -46,24 +46,19 @@ pub enum NodeIdHashingMode { /// We could also just store a plain reference to the `hir::Crate` but we want /// to avoid that the crate is used to get untracked access to all of the HIR. #[derive(Clone, Copy)] -pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>); - -impl<'tcx> BodyResolver<'tcx> { - /// Returns a reference to the `hir::Body` with the given `BodyId`. - /// **Does not do any tracking**; use carefully. - pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> { - self.0.body(id) - } +pub(super) enum BodyResolver<'tcx> { + Forbidden, + Traverse { + hash_bodies: bool, + owner: LocalDefId, + bodies: &'tcx IndexVec>>, + }, } impl<'a> StableHashingContext<'a> { - /// The `krate` here is only used for mapping `BodyId`s to `Body`s. - /// Don't use it for anything else or you'll run the risk of - /// leaking data out of the tracking system. #[inline] fn new_with_or_without_spans( sess: &'a Session, - krate: &'a hir::Crate<'a>, definitions: &'a Definitions, cstore: &'a dyn CrateStore, always_ignore_spans: bool, @@ -72,13 +67,12 @@ impl<'a> StableHashingContext<'a> { !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans; StableHashingContext { - body_resolver: BodyResolver(krate), + body_resolver: BodyResolver::Forbidden, definitions, cstore, caching_source_map: None, raw_source_map: sess.source_map(), hash_spans: hash_spans_initial, - hash_bodies: true, node_id_hashing_mode: NodeIdHashingMode::HashDefPath, } } @@ -86,13 +80,11 @@ impl<'a> StableHashingContext<'a> { #[inline] pub fn new( sess: &'a Session, - krate: &'a hir::Crate<'a>, definitions: &'a Definitions, cstore: &'a dyn CrateStore, ) -> Self { Self::new_with_or_without_spans( sess, - krate, definitions, cstore, /*always_ignore_spans=*/ false, @@ -102,20 +94,41 @@ impl<'a> StableHashingContext<'a> { #[inline] pub fn ignore_spans( sess: &'a Session, - krate: &'a hir::Crate<'a>, definitions: &'a Definitions, cstore: &'a dyn CrateStore, ) -> Self { let always_ignore_spans = true; - Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans) + Self::new_with_or_without_spans(sess, definitions, cstore, always_ignore_spans) } + /// Allow hashing #[inline] - pub fn while_hashing_hir_bodies(&mut self, hash_bodies: bool, f: F) { - let prev_hash_bodies = self.hash_bodies; - self.hash_bodies = hash_bodies; + pub fn while_hashing_hir_bodies(&mut self, hb: bool, f: impl FnOnce(&mut Self)) { + let prev = match &mut self.body_resolver { + BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."), + BodyResolver::Traverse { ref mut hash_bodies, .. } => { + std::mem::replace(hash_bodies, hb) + } + }; f(self); - self.hash_bodies = prev_hash_bodies; + match &mut self.body_resolver { + BodyResolver::Forbidden => unreachable!(), + BodyResolver::Traverse { ref mut hash_bodies, .. } => *hash_bodies = prev, + } + } + + #[inline] + pub fn with_hir_bodies( + &mut self, + hash_bodies: bool, + owner: LocalDefId, + bodies: &'a IndexVec>>, + f: impl FnOnce(&mut Self), + ) { + let prev = self.body_resolver; + self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies }; + f(self); + self.body_resolver = prev; } #[inline] @@ -152,11 +165,6 @@ impl<'a> StableHashingContext<'a> { self.definitions.def_path_hash(def_id) } - #[inline] - pub fn hash_bodies(&self) -> bool { - self.hash_bodies - } - #[inline] pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> { match self.caching_source_map { diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs index 04eb263a97718..dc208b36f938e 100644 --- a/compiler/rustc_query_system/src/ich/impls_hir.rs +++ b/compiler/rustc_query_system/src/ich/impls_hir.rs @@ -1,6 +1,7 @@ //! This module contains `HashStable` implementations for various HIR data //! types in no particular order. +use crate::ich::hcx::BodyResolver; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; @@ -29,8 +30,13 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { #[inline] fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) { let hcx = self; - if hcx.hash_bodies() { - hcx.body_resolver.body(id).hash_stable(hcx, hasher); + match hcx.body_resolver { + BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."), + BodyResolver::Traverse { hash_bodies: false, .. } => {} + BodyResolver::Traverse { hash_bodies: true, owner, bodies } => { + assert_eq!(id.hir_id.owner, owner); + bodies[id.hir_id.local_id].unwrap().hash_stable(hcx, hasher); + } } } diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index f1d3315d6e66a..bd27c16c732a9 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -23,6 +23,7 @@ rustc_feature = { path = "../rustc_feature" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_metadata = { path = "../rustc_metadata" } +rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 28fe365fb584b..f08878ea9255e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -54,13 +54,14 @@ use rustc_middle::hir::exports::ExportMap; use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; +use rustc_query_system::ich::StableHashingContext; use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, Transparency}; -use rustc_span::source_map::{CachingSourceMapView, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -1177,6 +1178,10 @@ impl ResolverAstLowering for Resolver<'_> { &mut self.definitions } + fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { + StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore()) + } + fn lint_buffer(&mut self) -> &mut LintBuffer { &mut self.lint_buffer } @@ -1245,37 +1250,6 @@ impl ResolverAstLowering for Resolver<'_> { } } -struct ExpandHasher<'a, 'b> { - source_map: CachingSourceMapView<'a>, - resolver: &'a Resolver<'b>, -} - -impl<'a, 'b> rustc_span::HashStableContext for ExpandHasher<'a, 'b> { - #[inline] - fn hash_spans(&self) -> bool { - true - } - - #[inline] - fn def_span(&self, id: LocalDefId) -> Span { - self.resolver.def_span(id) - } - - #[inline] - fn def_path_hash(&self, def_id: DefId) -> DefPathHash { - self.resolver.def_path_hash(def_id) - } - - #[inline] - fn span_data_to_lines_and_cols( - &mut self, - span: &rustc_span::SpanData, - ) -> Option<(Lrc, usize, rustc_span::BytePos, usize, rustc_span::BytePos)> - { - self.source_map.span_data_to_lines_and_cols(span) - } -} - impl<'a> Resolver<'a> { pub fn new( session: &'a Session, @@ -1456,13 +1430,6 @@ impl<'a> Resolver<'a> { self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map) } - fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> { - ExpandHasher { - source_map: CachingSourceMapView::new(self.session.source_map()), - resolver: self, - } - } - pub fn next_node_id(&mut self) -> NodeId { let next = self .next_node_id From ed3c8e86cbface5f050b8911b0de02c196d840eb Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 9 Oct 2021 19:44:55 +0200 Subject: [PATCH 06/17] Hash during lowering. --- compiler/rustc_ast_lowering/src/lib.rs | 27 ++++++++++++++++- compiler/rustc_hir/src/hir.rs | 5 ++++ .../rustc_middle/src/hir/map/collector.rs | 29 +++---------------- compiler/rustc_middle/src/hir/map/mod.rs | 2 -- 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 80b95b99b165e..f95ad9f3a9bd6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -41,7 +41,9 @@ use rustc_ast::visit; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; use rustc_data_structures::captures::Captures; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -467,7 +469,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - hir::OwnerInfo { node, attrs, bodies, trait_map } + let (hash, node_hash) = self.hash_body(node, &bodies); + + hir::OwnerInfo { hash, node_hash, node, attrs, bodies, trait_map } + } + + /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate + /// queries which depend on the full HIR tree and those which only depend on the item signature. + fn hash_body( + &mut self, + node: hir::OwnerNode<'hir>, + bodies: &IndexVec>>, + ) -> (Fingerprint, Fingerprint) { + let mut hcx = self.resolver.create_stable_hashing_context(); + let mut stable_hasher = StableHasher::new(); + hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| { + node.hash_stable(hcx, &mut stable_hasher) + }); + let full_hash = stable_hasher.finish(); + let mut stable_hasher = StableHasher::new(); + hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| { + node.hash_stable(hcx, &mut stable_hasher) + }); + let node_hash = stable_hasher.finish(); + (full_hash, node_hash) } /// This method allocates a new `HirId` for the given `NodeId` and stores it in diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1d1c0a0de13d8..44652d0198fad 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -9,6 +9,7 @@ use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObject pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto}; pub use rustc_ast::{CaptureBy, Movability, Mutability}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; @@ -670,6 +671,10 @@ pub struct OwnerInfo<'hir> { /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. pub trait_map: FxHashMap>, + /// Pre-computed hash of the full HIR. + pub hash: Fingerprint, + /// Pre-computed hash of the top node. + pub node_hash: Fingerprint, } /// The top-level data structure that stores the entire contents of diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 80e48a4f74b4f..2499ef8bc60d1 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -1,9 +1,7 @@ use crate::arena::Arena; use crate::hir::map::Map; use crate::hir::{IndexedHir, OwnerNodes, ParentedNode}; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; @@ -11,7 +9,6 @@ use rustc_hir::definitions; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::*; use rustc_index::vec::{Idx, IndexVec}; -use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::{Span, DUMMY_SP}; @@ -37,8 +34,6 @@ pub(super) struct NodeCollector<'a, 'hir> { current_dep_node_owner: LocalDefId, definitions: &'a definitions::Definitions, - - hcx: StableHashingContext<'a>, } fn insert_vec_map(map: &mut IndexVec>, k: K, v: V) { @@ -51,27 +46,12 @@ fn insert_vec_map(map: &mut IndexVec>, k: K, v: V map[k] = Some(v); } -fn hash_body<'s, 'hir: 's>( - hcx: &mut StableHashingContext<'s>, - item_like: impl for<'a> HashStable>, - hash_bodies: bool, - owner: LocalDefId, - bodies: &'hir IndexVec>>, -) -> Fingerprint { - let mut stable_hasher = StableHasher::new(); - hcx.with_hir_bodies(hash_bodies, owner, bodies, |hcx| { - item_like.hash_stable(hcx, &mut stable_hasher) - }); - stable_hasher.finish() -} - impl<'a, 'hir: 'a> NodeCollector<'a, 'hir> { pub(super) fn root( sess: &'a Session, arena: &'hir Arena<'hir>, krate: &'hir Crate<'hir>, definitions: &'a definitions::Definitions, - hcx: StableHashingContext<'a>, ) -> NodeCollector<'a, 'hir> { let mut collector = NodeCollector { arena, @@ -80,7 +60,6 @@ impl<'a, 'hir: 'a> NodeCollector<'a, 'hir> { parent_node: hir::CRATE_HIR_ID, current_dep_node_owner: CRATE_DEF_ID, definitions, - hcx, map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()), parenting: FxHashMap::default(), }; @@ -97,10 +76,10 @@ impl<'a, 'hir: 'a> NodeCollector<'a, 'hir> { let mut nodes = IndexVec::new(); nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() })); - let bodies = &self.krate.owners[owner].as_ref().unwrap().bodies; - - let hash = hash_body(&mut self.hcx, node, true, owner, bodies); - let node_hash = hash_body(&mut self.hcx, node, false, owner, bodies); + let info = self.krate.owners[owner].as_ref().unwrap(); + let hash = info.hash; + let node_hash = info.node_hash; + let bodies = &info.bodies; debug_assert!(self.map[owner].is_none()); self.map[owner] = Some(self.arena.alloc(OwnerNodes { hash, node_hash, nodes, bodies })); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8c11fd8a280fc..89f4ec4d9f61f 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1071,13 +1071,11 @@ pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx IndexedHir<'tc let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map"); // We can access untracked state since we are an eval_always query. - let hcx = tcx.create_stable_hashing_context(); let mut collector = NodeCollector::root( tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.untracked_resolutions.definitions, - hcx, ); let top_mod = tcx.untracked_crate.module(); collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID); From c09eaea484c8f7a01741188982447eec88b5caa8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 28 Feb 2021 20:23:10 +0100 Subject: [PATCH 07/17] Make index_hir incremental. --- compiler/rustc_hir/src/definitions.rs | 6 + compiler/rustc_middle/src/arena.rs | 5 +- .../rustc_middle/src/hir/map/collector.rs | 164 ++++++++---------- compiler/rustc_middle/src/hir/map/mod.rs | 43 ++--- compiler/rustc_middle/src/hir/mod.rs | 36 ++-- compiler/rustc_middle/src/query/mod.rs | 3 +- 6 files changed, 115 insertions(+), 142 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index ca29351455e62..b7bdc9a1414ac 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -92,6 +92,12 @@ impl DefPathTable { .iter_enumerated() .map(move |(index, key)| (index, key, &self.def_path_hashes[index])) } + + pub fn all_def_path_hashes_and_def_ids( + &self, + ) -> impl Iterator + '_ { + self.def_path_hashes.iter_enumerated().map(move |(index, hash)| (hash, index)) + } } /// The definition table containing node definitions. diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 962aea448b82c..2986e8c7a06db 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -93,10 +93,7 @@ macro_rules! arena_types { [] predicates: rustc_middle::ty::PredicateInner<$tcx>, // HIR query types - [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>, - [few] hir_definitions: rustc_hir::definitions::Definitions, - [] hir_owner: rustc_middle::hir::Owner<$tcx>, - [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>, + [] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 2499ef8bc60d1..a9e676b9e30f4 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -1,10 +1,8 @@ -use crate::arena::Arena; use crate::hir::map::Map; use crate::hir::{IndexedHir, OwnerNodes, ParentedNode}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::definitions; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::*; @@ -17,21 +15,19 @@ use std::iter::repeat; /// A visitor that walks over the HIR and collects `Node`s into a HIR map. pub(super) struct NodeCollector<'a, 'hir> { - arena: &'hir Arena<'hir>, - /// The crate krate: &'hir Crate<'hir>, /// Source map source_map: &'a SourceMap, - map: IndexVec>>, - parenting: FxHashMap, + nodes: OwnerNodes<'hir>, + parenting: FxHashMap, /// The parent of this node - parent_node: hir::HirId, + parent_node: hir::ItemLocalId, - current_dep_node_owner: LocalDefId, + owner: LocalDefId, definitions: &'a definitions::Definitions, } @@ -46,53 +42,51 @@ fn insert_vec_map(map: &mut IndexVec>, k: K, v: V map[k] = Some(v); } -impl<'a, 'hir: 'a> NodeCollector<'a, 'hir> { - pub(super) fn root( - sess: &'a Session, - arena: &'hir Arena<'hir>, - krate: &'hir Crate<'hir>, - definitions: &'a definitions::Definitions, - ) -> NodeCollector<'a, 'hir> { - let mut collector = NodeCollector { - arena, - krate, - source_map: sess.source_map(), - parent_node: hir::CRATE_HIR_ID, - current_dep_node_owner: CRATE_DEF_ID, - definitions, - map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()), - parenting: FxHashMap::default(), - }; - collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module())); - - collector - } - - pub(super) fn finalize_and_compute_crate_hash(self) -> IndexedHir<'hir> { - IndexedHir { map: self.map, parenting: self.parenting } - } - - fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) { - let mut nodes = IndexVec::new(); - nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() })); - - let info = self.krate.owners[owner].as_ref().unwrap(); - let hash = info.hash; - let node_hash = info.node_hash; - let bodies = &info.bodies; - - debug_assert!(self.map[owner].is_none()); - self.map[owner] = Some(self.arena.alloc(OwnerNodes { hash, node_hash, nodes, bodies })); - } +pub(super) fn collect<'a, 'hir: 'a>( + sess: &'a Session, + krate: &'hir Crate<'hir>, + definitions: &'a definitions::Definitions, + owner: LocalDefId, +) -> Option> { + let info = krate.owners.get(owner)?.as_ref()?; + let item = info.node; + let mut nodes = IndexVec::new(); + nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: item.into() })); + let mut collector = NodeCollector { + krate, + source_map: sess.source_map(), + owner, + parent_node: ItemLocalId::new(0), + definitions, + nodes: OwnerNodes { + hash: info.hash, + node_hash: info.node_hash, + nodes, + bodies: &info.bodies, + }, + parenting: FxHashMap::default(), + }; + + match item { + OwnerNode::Crate(citem) => collector.visit_mod(&citem, citem.inner, hir::CRATE_HIR_ID), + OwnerNode::Item(item) => collector.visit_item(item), + OwnerNode::TraitItem(item) => collector.visit_trait_item(item), + OwnerNode::ImplItem(item) => collector.visit_impl_item(item), + OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item), + }; + + Some(IndexedHir { nodes: collector.nodes, parenting: collector.parenting }) +} +impl<'a, 'hir> NodeCollector<'a, 'hir> { fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { - debug_assert_eq!(self.current_dep_node_owner, hir_id.owner); + debug_assert_eq!(self.owner, hir_id.owner); debug_assert_ne!(hir_id.local_id.as_u32(), 0); // Make sure that the DepNode of some node coincides with the HirId // owner of that node. if cfg!(debug_assertions) { - if hir_id.owner != self.current_dep_node_owner { + if hir_id.owner != self.owner { let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(), None => format!("{:?}", node), @@ -104,62 +98,41 @@ impl<'a, 'hir: 'a> NodeCollector<'a, 'hir> { current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", self.source_map.span_to_diagnostic_string(span), node_str, - self.definitions - .def_path(self.current_dep_node_owner) - .to_string_no_crate_verbose(), - self.current_dep_node_owner, + self.definitions.def_path(self.owner).to_string_no_crate_verbose(), + self.owner, self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(), hir_id.owner, ) } } - let nodes = self.map[hir_id.owner].as_mut().unwrap(); - - debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner); insert_vec_map( - &mut nodes.nodes, + &mut self.nodes.nodes, hir_id.local_id, - ParentedNode { parent: self.parent_node.local_id, node: node }, + ParentedNode { parent: self.parent_node, node: node }, ); } fn with_parent(&mut self, parent_node_id: HirId, f: F) { + debug_assert_eq!(parent_node_id.owner, self.owner); let parent_node = self.parent_node; - self.parent_node = parent_node_id; + self.parent_node = parent_node_id.local_id; f(self); self.parent_node = parent_node; } - fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) { - let prev_owner = self.current_dep_node_owner; - let prev_parent = self.parent_node; - - self.current_dep_node_owner = dep_node_owner; - self.parent_node = HirId::make_owner(dep_node_owner); - f(self); - self.current_dep_node_owner = prev_owner; - self.parent_node = prev_parent; - } - fn insert_nested(&mut self, item: LocalDefId) { - #[cfg(debug_assertions)] - { - let dk_parent = self.definitions.def_key(item).parent.unwrap(); - let dk_parent = LocalDefId { local_def_index: dk_parent }; - let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent); - debug_assert_eq!( - dk_parent.owner, self.parent_node.owner, - "Different parents for {:?}", - item - ) + let dk_parent = self.definitions.def_key(item).parent.unwrap(); + let dk_parent = LocalDefId { local_def_index: dk_parent }; + let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent); + debug_assert_eq!(dk_parent.owner, self.owner, "Different parents for {:?}", item); + if dk_parent.local_id != self.parent_node { + self.parenting.insert(item, self.parent_node); } - - assert_eq!(self.parenting.insert(item, self.parent_node), None); } } -impl<'a, 'hir: 'a> Visitor<'hir> for NodeCollector<'a, 'hir> { +impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { type Map = Map<'hir>; /// Because we want to track parent items and so forth, enable @@ -173,26 +146,24 @@ impl<'a, 'hir: 'a> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); self.insert_nested(item.def_id); - self.visit_item(self.krate.item(item)); } fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { self.insert_nested(item_id.def_id); - self.visit_trait_item(self.krate.trait_item(item_id)); } fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { self.insert_nested(item_id.def_id); - self.visit_impl_item(self.krate.impl_item(item_id)); } fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) { self.insert_nested(foreign_id.def_id); - self.visit_foreign_item(self.krate.foreign_item(foreign_id)); } fn visit_nested_body(&mut self, id: BodyId) { - self.visit_body(self.krate.body(id)); + let body = self.krate.body(id); + debug_assert_eq!(id.hir_id.owner, self.owner); + self.visit_body(body); } fn visit_param(&mut self, param: &'hir Param<'hir>) { @@ -205,8 +176,8 @@ impl<'a, 'hir: 'a> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_item(&mut self, i: &'hir Item<'hir>) { debug!("visit_item: {:?}", i); - self.insert_owner(i.def_id, OwnerNode::Item(i)); - self.with_dep_node_owner(i.def_id, |this| { + debug_assert_eq!(i.def_id, self.owner); + self.with_parent(i.hir_id(), |this| { if let ItemKind::Struct(ref struct_def, _) = i.kind { // If this is a tuple or unit-like struct, register the constructor. if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { @@ -218,8 +189,8 @@ impl<'a, 'hir: 'a> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { - self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi)); - self.with_dep_node_owner(fi.def_id, |this| { + debug_assert_eq!(fi.def_id, self.owner); + self.with_parent(fi.hir_id(), |this| { intravisit::walk_foreign_item(this, fi); }); } @@ -236,15 +207,15 @@ impl<'a, 'hir: 'a> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { - self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti)); - self.with_dep_node_owner(ti.def_id, |this| { + debug_assert_eq!(ti.def_id, self.owner); + self.with_parent(ti.hir_id(), |this| { intravisit::walk_trait_item(this, ti); }); } fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { - self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii)); - self.with_dep_node_owner(ii.def_id, |this| { + debug_assert_eq!(ii.def_id, self.owner); + self.with_parent(ii.hir_id(), |this| { intravisit::walk_impl_item(this, ii); }); } @@ -332,7 +303,8 @@ impl<'a, 'hir: 'a> Visitor<'hir> for NodeCollector<'a, 'hir> { s: Span, id: HirId, ) { - assert_eq!(self.parent_node, id); + assert_eq!(self.owner, id.owner); + assert_eq!(self.parent_node, id.local_id); intravisit::walk_fn(self, fk, fd, b, s, id); } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 89f4ec4d9f61f..1a63cc1d8fedd 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,5 +1,3 @@ -use self::collector::NodeCollector; - use crate::hir::{IndexedHir, ModuleItems, Owner}; use crate::ty::TyCtxt; use rustc_ast as ast; @@ -318,7 +316,7 @@ impl<'hir> Map<'hir> { } pub fn get_parent_node(&self, hir_id: HirId) -> HirId { - self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID) + self.find_parent_node(hir_id).unwrap() } /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. @@ -1067,36 +1065,30 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx IndexedHir<'tcx> { - let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map"); - - // We can access untracked state since we are an eval_always query. - let mut collector = NodeCollector::root( +pub(super) fn index_hir<'tcx>( + tcx: TyCtxt<'tcx>, + owner: LocalDefId, +) -> Option<&'tcx IndexedHir<'tcx>> { + let map = collector::collect( tcx.sess, - &**tcx.arena, tcx.untracked_crate, &tcx.untracked_resolutions.definitions, - ); - let top_mod = tcx.untracked_crate.module(); - collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID); + owner, + )?; - let map = collector.finalize_and_compute_crate_hash(); - tcx.arena.alloc(map) + Some(&*tcx.arena.alloc(map)) } pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { - assert_eq!(crate_num, LOCAL_CRATE); - - // We can access untracked state since we are an eval_always query. - let mut hcx = tcx.create_stable_hashing_context(); - + debug_assert_eq!(crate_num, LOCAL_CRATE); let mut hir_body_nodes: Vec<_> = tcx - .index_hir(()) - .map - .iter_enumerated() - .filter_map(|(def_id, hod)| { - let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id); - let hash = hod.as_ref()?.hash; + .untracked_resolutions + .definitions + .def_path_table() + .all_def_path_hashes_and_def_ids() + .filter_map(|(def_path_hash, local_def_index)| { + let def_id = LocalDefId { local_def_index }; + let hash = tcx.index_hir(def_id).as_ref()?.nodes.hash; Some((def_path_hash, hash, def_id)) }) .collect(); @@ -1120,6 +1112,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { source_file_names.sort_unstable(); + let mut hcx = tcx.create_stable_hashing_context(); let mut stable_hasher = StableHasher::new(); for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() { def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 6d24190eefb5c..2ac647307184e 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -19,16 +19,13 @@ use rustc_query_system::ich::StableHashingContext; use rustc_span::DUMMY_SP; use std::collections::BTreeMap; -/// Result of HIR indexing. -#[derive(Debug)] +/// Result of HIR indexing for a given HIR owner. +#[derive(Debug, HashStable)] pub struct IndexedHir<'hir> { - /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners. - // The `mut` comes from construction time, and is harmless since we only ever hand out - // immutable refs to IndexedHir. - map: IndexVec>>, - /// Map from each owner to its parent's HirId inside another owner. - // This map is separate from `map` to eventually allow for per-owner indexing. - parenting: FxHashMap, + /// Contents of the HIR. + nodes: OwnerNodes<'hir>, + /// Map from each nested owner to its parent's local id. + parenting: FxHashMap, } /// Top-level HIR node for current owner. This only contains the node for which @@ -132,15 +129,24 @@ pub fn provide(providers: &mut Providers) { providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; providers.hir_owner = |tcx, id| { - let owner = tcx.index_hir(()).map[id].as_ref()?; - let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; + let owner = tcx.index_hir(id)?; + let node = owner.nodes.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. - Some(Owner { node, node_hash: owner.node_hash }) + Some(Owner { node, node_hash: owner.nodes.node_hash }) }; - providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref(); + providers.hir_owner_nodes = |tcx, id| tcx.index_hir(id).map(|i| &i.nodes); providers.hir_owner_parent = |tcx, id| { - let index = tcx.index_hir(()); - index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) + let parent = tcx.untracked_resolutions.definitions.def_key(id).parent; + let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| { + let def_id = LocalDefId { local_def_index }; + let mut parent_hir_id = + tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id); + if let Some(local_id) = tcx.index_hir(parent_hir_id.owner).unwrap().parenting.get(&id) { + parent_hir_id.local_id = *local_id; + } + parent_hir_id + }); + parent }; providers.hir_attrs = |tcx, id| AttributeMap::new(&tcx.hir_crate(()).owners[id]); providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7e9391b98f7ed..bfded8f710ac8 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -42,9 +42,8 @@ rustc_queries! { /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. /// Avoid calling this query directly. - query index_hir(_: ()) -> &'tcx crate::hir::IndexedHir<'tcx> { + query index_hir(_: LocalDefId) -> Option<&'tcx crate::hir::IndexedHir<'tcx>> { eval_always - no_hash desc { "index HIR" } } From 1c7f85f17c0ddde890ced0ba4445e122c1ffc093 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 12 Sep 2021 03:19:18 +0200 Subject: [PATCH 08/17] Perform indexing during lowering. Do not access DefId<->HirId maps before they are initialized. --- .../src/index.rs} | 65 ++++++---------- compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 8 +- compiler/rustc_hir/src/arena.rs | 1 + compiler/rustc_hir/src/hir.rs | 78 +++++++++---------- compiler/rustc_hir/src/intravisit.rs | 22 ++++++ compiler/rustc_hir/src/lib.rs | 1 + compiler/rustc_hir/src/stable_hash_impls.rs | 13 +++- compiler/rustc_middle/src/arena.rs | 3 - compiler/rustc_middle/src/hir/map/mod.rs | 29 ++----- compiler/rustc_middle/src/hir/mod.rs | 55 ++----------- compiler/rustc_middle/src/query/mod.rs | 9 +-- 12 files changed, 117 insertions(+), 169 deletions(-) rename compiler/{rustc_middle/src/hir/map/collector.rs => rustc_ast_lowering/src/index.rs} (87%) diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_ast_lowering/src/index.rs similarity index 87% rename from compiler/rustc_middle/src/hir/map/collector.rs rename to compiler/rustc_ast_lowering/src/index.rs index a9e676b9e30f4..7b0f1caaee1e1 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -1,5 +1,3 @@ -use crate::hir::map::Map; -use crate::hir::{IndexedHir, OwnerNodes, ParentedNode}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -12,16 +10,16 @@ use rustc_span::source_map::SourceMap; use rustc_span::{Span, DUMMY_SP}; use std::iter::repeat; +use tracing::debug; /// A visitor that walks over the HIR and collects `Node`s into a HIR map. pub(super) struct NodeCollector<'a, 'hir> { - /// The crate - krate: &'hir Crate<'hir>, - /// Source map source_map: &'a SourceMap, + bodies: &'a IndexVec>>, - nodes: OwnerNodes<'hir>, + /// Outputs + nodes: IndexVec>>, parenting: FxHashMap, /// The parent of this node @@ -42,28 +40,21 @@ fn insert_vec_map(map: &mut IndexVec>, k: K, v: V map[k] = Some(v); } -pub(super) fn collect<'a, 'hir: 'a>( - sess: &'a Session, - krate: &'hir Crate<'hir>, - definitions: &'a definitions::Definitions, - owner: LocalDefId, -) -> Option> { - let info = krate.owners.get(owner)?.as_ref()?; - let item = info.node; +pub(super) fn index_hir<'hir>( + sess: &Session, + definitions: &definitions::Definitions, + item: hir::OwnerNode<'hir>, + bodies: &IndexVec>>, +) -> (IndexVec>>, FxHashMap) { let mut nodes = IndexVec::new(); nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: item.into() })); let mut collector = NodeCollector { - krate, source_map: sess.source_map(), - owner, - parent_node: ItemLocalId::new(0), definitions, - nodes: OwnerNodes { - hash: info.hash, - node_hash: info.node_hash, - nodes, - bodies: &info.bodies, - }, + owner: item.def_id(), + parent_node: ItemLocalId::new(0), + nodes, + bodies, parenting: FxHashMap::default(), }; @@ -75,7 +66,7 @@ pub(super) fn collect<'a, 'hir: 'a>( OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item), }; - Some(IndexedHir { nodes: collector.nodes, parenting: collector.parenting }) + (collector.nodes, collector.parenting) } impl<'a, 'hir> NodeCollector<'a, 'hir> { @@ -87,17 +78,11 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // owner of that node. if cfg!(debug_assertions) { if hir_id.owner != self.owner { - let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { - Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(), - None => format!("{:?}", node), - }; - - span_bug!( - span, - "inconsistent DepNode at `{:?}` for `{}`: \ + panic!( + "inconsistent DepNode at `{:?}` for `{:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", self.source_map.span_to_diagnostic_string(span), - node_str, + node, self.definitions.def_path(self.owner).to_string_no_crate_verbose(), self.owner, self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(), @@ -107,7 +92,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } insert_vec_map( - &mut self.nodes.nodes, + &mut self.nodes, hir_id.local_id, ParentedNode { parent: self.parent_node, node: node }, ); @@ -122,18 +107,12 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } fn insert_nested(&mut self, item: LocalDefId) { - let dk_parent = self.definitions.def_key(item).parent.unwrap(); - let dk_parent = LocalDefId { local_def_index: dk_parent }; - let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent); - debug_assert_eq!(dk_parent.owner, self.owner, "Different parents for {:?}", item); - if dk_parent.local_id != self.parent_node { - self.parenting.insert(item, self.parent_node); - } + self.parenting.insert(item, self.parent_node); } } impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { - type Map = Map<'hir>; + type Map = !; /// Because we want to track parent items and so forth, enable /// deep walking so that we walk nested items in the context of @@ -161,8 +140,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_nested_body(&mut self, id: BodyId) { - let body = self.krate.body(id); debug_assert_eq!(id.hir_id.owner, self.owner); + let body = self.bodies[id.hir_id.local_id].unwrap(); self.visit_body(body); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index cac5bb56c9f5f..d5fa52a341475 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -101,7 +101,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let old_len = self.in_scope_lifetimes.len(); let parent_generics = - match self.owners[parent_hir_id].as_ref().unwrap().node.expect_item().kind { + match self.owners[parent_hir_id].as_ref().unwrap().node().expect_item().kind { hir::ItemKind::Impl(hir::Impl { ref generics, .. }) | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, _ => &[], diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f95ad9f3a9bd6..a7f1ba8b79198 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -33,6 +33,7 @@ #![feature(crate_visibility_modifier)] #![feature(box_patterns)] #![feature(iter_zip)] +#![feature(never_type)] #![recursion_limit = "256"] use rustc_ast::token::{self, Token}; @@ -78,6 +79,7 @@ macro_rules! arena_vec { mod asm; mod block; mod expr; +mod index; mod item; mod pat; mod path; @@ -434,6 +436,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.local_node_ids.push(owner); let item = f(self); + debug_assert_eq!(def_id, item.def_id()); let info = self.make_owner_info(item); self.attrs = current_attrs; @@ -470,8 +473,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let (hash, node_hash) = self.hash_body(node, &bodies); + let (nodes, parenting) = + index::index_hir(self.sess, self.resolver.definitions(), node, &bodies); + let nodes = hir::OwnerNodes { hash, node_hash, nodes, bodies }; - hir::OwnerInfo { hash, node_hash, node, attrs, bodies, trait_map } + hir::OwnerInfo { nodes, parenting, attrs, trait_map } } /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index 5334f6d729dc5..1a34dd0442855 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -37,6 +37,7 @@ macro_rules! arena_types { [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, [] local: rustc_hir::Local<$tcx>, [few] mod_: rustc_hir::Mod<$tcx>, + [] owner_info: rustc_hir::OwnerInfo<$tcx>, [] param: rustc_hir::Param<$tcx>, [] pat: rustc_hir::Pat<$tcx>, [] path: rustc_hir::Path<$tcx>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 44652d0198fad..4c8157fee3704 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,5 +1,5 @@ use crate::def::{CtorKind, DefKind, Res}; -use crate::def_id::{DefId, CRATE_DEF_ID}; +use crate::def_id::DefId; crate use crate::hir_id::{HirId, ItemLocalId}; use crate::LangItem; @@ -663,18 +663,49 @@ pub struct WhereEqPredicate<'hir> { pub rhs_ty: &'hir Ty<'hir>, } +/// HIR node coupled with its parent's id in the same HIR owner. +/// +/// The parent is trash when the node is a HIR owner. +#[derive(Clone, Debug)] +pub struct ParentedNode<'tcx> { + pub parent: ItemLocalId, + pub node: Node<'tcx>, +} + +#[derive(Debug)] +pub struct OwnerNodes<'tcx> { + /// Pre-computed hash of the full HIR. + pub hash: Fingerprint, + /// Pre-computed hash of the top node. + pub node_hash: Fingerprint, + /// Full HIR for the current owner. + // The zeroth node's parent is trash, but is never accessed. + pub nodes: IndexVec>>, + /// Content of local bodies. + pub bodies: IndexVec>>, +} + #[derive(Debug)] pub struct OwnerInfo<'hir> { - pub node: OwnerNode<'hir>, + /// Contents of the HIR. + pub nodes: OwnerNodes<'hir>, + /// Map from each nested owner to its parent's local id. + pub parenting: FxHashMap, + pub attrs: BTreeMap, - pub bodies: IndexVec>>, /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. pub trait_map: FxHashMap>, - /// Pre-computed hash of the full HIR. - pub hash: Fingerprint, - /// Pre-computed hash of the top node. - pub node_hash: Fingerprint, +} + +impl<'tcx> OwnerInfo<'tcx> { + #[inline] + pub fn node(&self) -> OwnerNode<'tcx> { + use rustc_index::vec::Idx; + let node = self.nodes.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; + let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. + node + } } /// The top-level data structure that stores the entire contents of @@ -688,39 +719,6 @@ pub struct Crate<'hir> { pub owners: IndexVec>>, } -impl Crate<'hir> { - pub fn module(&self) -> &'hir Mod<'hir> { - let i = self.owners[CRATE_DEF_ID].as_ref().unwrap().node; - if let OwnerNode::Crate(m) = i { m } else { panic!() } - } - - pub fn item(&self, id: ItemId) -> &'hir Item<'hir> { - self.owners[id.def_id].as_ref().unwrap().node.expect_item() - } - - pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().node.expect_trait_item() - } - - pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().node.expect_impl_item() - } - - pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> { - self.owners[id.def_id].as_ref().unwrap().node.expect_foreign_item() - } - - pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { - let HirId { owner, local_id } = id.hir_id; - self.owners[owner].as_ref().unwrap().bodies[local_id].unwrap() - } - - pub fn attrs(&self, id: HirId) -> &'hir [Attribute] { - let HirId { owner, local_id } = id; - &self.owners[owner].as_ref().unwrap().attrs.get(&local_id).map(|la| *la).unwrap_or(&[]) - } -} - /// A block of statements `{ .. }`, which may have a label (in this case the /// `targeted_by_break` field will be `true`) and may be `unsafe` by means of /// the `rules` being anything but `DefaultBlock`. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1ac2625dd4754..3e58af1f167aa 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -130,6 +130,28 @@ pub trait Map<'hir> { fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>; } +// Used when no map is actually available, forcing manual implementation of nested visitors. +impl Map<'hir> for ! { + fn find(&self, _: HirId) -> Option> { + unreachable!() + } + fn body(&self, _: BodyId) -> &'hir Body<'hir> { + unreachable!() + } + fn item(&self, _: ItemId) -> &'hir Item<'hir> { + unreachable!() + } + fn trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> { + unreachable!() + } + fn impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> { + unreachable!() + } + fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> { + unreachable!() + } +} + /// An erased version of `Map<'hir>`, using dynamic dispatch. /// NOTE: This type is effectively only usable with `NestedVisitorMap::None`. pub struct ErasedMap<'hir>(&'hir dyn Map<'hir>); diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index f5ea044e24865..af8421aeb89a7 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -6,6 +6,7 @@ #![feature(in_band_lifetimes)] #![feature(once_cell)] #![feature(min_specialization)] +#![feature(never_type)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 9d5ef279dd784..ad73e363d7f2e 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,8 +1,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use crate::hir::{ - BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, - TraitItemId, Ty, VisibilityKind, + BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, OwnerNodes, + TraitItem, TraitItemId, Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::DefPathHash; @@ -209,3 +209,12 @@ impl HashStable for Item<'_> { }); } } + +impl HashStable for OwnerNodes<'tcx> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + // We ignore the `nodes` and `bodies` fields since these refer to information included in + // `hash` which is hashed in the collector and used for the crate hash. + let OwnerNodes { hash, node_hash: _, nodes: _, bodies: _ } = *self; + hash.hash_stable(hcx, hasher); + } +} diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 2986e8c7a06db..4a027cb7ebe05 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -92,9 +92,6 @@ macro_rules! arena_types { [] tys: rustc_middle::ty::TyS<$tcx>, [] predicates: rustc_middle::ty::PredicateInner<$tcx>, - // HIR query types - [] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>, - // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena // (during lowering) and the `librustc_middle` arena (for decoding MIR) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 1a63cc1d8fedd..834d5f964e187 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,4 +1,4 @@ -use crate::hir::{IndexedHir, ModuleItems, Owner}; +use crate::hir::{ModuleItems, Owner}; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; @@ -21,7 +21,6 @@ use rustc_target::spec::abi::Abi; use std::collections::VecDeque; pub mod blocks; -mod collector; fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { match node { @@ -164,7 +163,7 @@ impl<'hir> Map<'hir> { pub fn items(&self) -> impl Iterator> + 'hir { let krate = self.krate(); - krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node { + krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node() { OwnerNode::Item(item) => Some(item), _ => None, }) @@ -497,7 +496,7 @@ impl<'hir> Map<'hir> { .owners .iter_enumerated() .flat_map(move |(owner, owner_info)| { - let bodies = &owner_info.as_ref()?.bodies; + let bodies = &owner_info.as_ref()?.nodes.bodies; Some(bodies.iter_enumerated().filter_map(move |(local_id, body)| { if body.is_none() { return None; @@ -518,7 +517,7 @@ impl<'hir> Map<'hir> { par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| { let owner = LocalDefId::new(owner); if let Some(owner_info) = owner_info { - par_iter(&owner_info.bodies.raw).enumerate().for_each(|(local_id, body)| { + par_iter(&owner_info.nodes.bodies.raw).enumerate().for_each(|(local_id, body)| { if body.is_some() { let local_id = ItemLocalId::new(local_id); let hir_id = HirId { owner, local_id }; @@ -605,7 +604,7 @@ impl<'hir> Map<'hir> { { let krate = self.krate(); for owner in krate.owners.iter().filter_map(Option::as_ref) { - match owner.node { + match owner.node() { OwnerNode::Item(item) => visitor.visit_item(item), OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), @@ -621,7 +620,7 @@ impl<'hir> Map<'hir> { V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, { let krate = self.krate(); - par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref().map(|o| o.node) { + par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref().map(OwnerInfo::node) { Some(OwnerNode::Item(item)) => visitor.visit_item(item), Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), @@ -1065,20 +1064,6 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub(super) fn index_hir<'tcx>( - tcx: TyCtxt<'tcx>, - owner: LocalDefId, -) -> Option<&'tcx IndexedHir<'tcx>> { - let map = collector::collect( - tcx.sess, - tcx.untracked_crate, - &tcx.untracked_resolutions.definitions, - owner, - )?; - - Some(&*tcx.arena.alloc(map)) -} - pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { debug_assert_eq!(crate_num, LOCAL_CRATE); let mut hir_body_nodes: Vec<_> = tcx @@ -1088,7 +1073,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { .all_def_path_hashes_and_def_ids() .filter_map(|(def_path_hash, local_def_index)| { let def_id = LocalDefId { local_def_index }; - let hash = tcx.index_hir(def_id).as_ref()?.nodes.hash; + let hash = tcx.hir_crate(()).owners[def_id].as_ref()?.nodes.hash; Some((def_path_hash, hash, def_id)) }) .collect(); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 2ac647307184e..70179e73b1975 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -10,24 +10,13 @@ use crate::ty::query::Providers; use crate::ty::TyCtxt; use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::LocalDefId; use rustc_hir::*; -use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; use rustc_span::DUMMY_SP; use std::collections::BTreeMap; -/// Result of HIR indexing for a given HIR owner. -#[derive(Debug, HashStable)] -pub struct IndexedHir<'hir> { - /// Contents of the HIR. - nodes: OwnerNodes<'hir>, - /// Map from each nested owner to its parent's local id. - parenting: FxHashMap, -} - /// Top-level HIR node for current owner. This only contains the node for which /// `HirId::local_id == 0`, and excludes bodies. /// @@ -47,38 +36,6 @@ impl<'a, 'tcx> HashStable> for Owner<'tcx> { } } -/// HIR node coupled with its parent's id in the same HIR owner. -/// -/// The parent is trash when the node is a HIR owner. -#[derive(Clone, Debug)] -pub struct ParentedNode<'tcx> { - parent: ItemLocalId, - node: Node<'tcx>, -} - -#[derive(Debug)] -pub struct OwnerNodes<'tcx> { - /// Pre-computed hash of the full HIR. - hash: Fingerprint, - /// Pre-computed hash of the top node. - node_hash: Fingerprint, - /// Full HIR for the current owner. - // The zeroth node's parent is trash, but is never accessed. - nodes: IndexVec>>, - /// Content of local bodies. - bodies: &'tcx IndexVec>>, -} - -impl<'a, 'tcx> HashStable> for OwnerNodes<'tcx> { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - // We ignore the `nodes` and `bodies` fields since these refer to information included in - // `hash` which is hashed in the collector and used for the crate hash. - let OwnerNodes { hash, node_hash: _, nodes: _, bodies: _ } = *self; - hash.hash_stable(hcx, hasher); - } -} - /// Attributes owner by a HIR owner. #[derive(Copy, Clone, Debug, HashStable)] pub struct AttributeMap<'tcx> { @@ -125,23 +82,23 @@ pub fn provide(providers: &mut Providers) { hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))) }; providers.hir_crate = |tcx, ()| tcx.untracked_crate; - providers.index_hir = map::index_hir; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; providers.hir_owner = |tcx, id| { - let owner = tcx.index_hir(id)?; - let node = owner.nodes.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; - let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. + let owner = tcx.hir_crate(()).owners[id].as_ref()?; + let node = owner.node(); Some(Owner { node, node_hash: owner.nodes.node_hash }) }; - providers.hir_owner_nodes = |tcx, id| tcx.index_hir(id).map(|i| &i.nodes); + providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes); providers.hir_owner_parent = |tcx, id| { let parent = tcx.untracked_resolutions.definitions.def_key(id).parent; let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| { let def_id = LocalDefId { local_def_index }; let mut parent_hir_id = tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id); - if let Some(local_id) = tcx.index_hir(parent_hir_id.owner).unwrap().parenting.get(&id) { + if let Some(local_id) = + tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id) + { parent_hir_id.local_id = *local_id; } parent_hir_id diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index bfded8f710ac8..e604f59175e8e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -40,13 +40,6 @@ rustc_queries! { desc { "get the crate HIR" } } - /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. - /// Avoid calling this query directly. - query index_hir(_: LocalDefId) -> Option<&'tcx crate::hir::IndexedHir<'tcx>> { - eval_always - desc { "index HIR" } - } - /// The items in a module. /// /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. @@ -76,7 +69,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { + query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> { desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } } From 41e80b85cf05e6373b589b876d3ee65823196406 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 12 Sep 2021 11:41:35 +0200 Subject: [PATCH 09/17] Directly use AttributeMap inside OwnerInfo. --- compiler/rustc_ast_lowering/src/lib.rs | 7 +++++++ compiler/rustc_hir/src/hir.rs | 21 +++++++++++++++++-- compiler/rustc_hir/src/lib.rs | 1 + compiler/rustc_hir/src/stable_hash_impls.rs | 13 ++++++++++-- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- compiler/rustc_middle/src/hir/mod.rs | 23 ++------------------- compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_middle/src/query/mod.rs | 2 +- 8 files changed, 42 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a7f1ba8b79198..9ba3d0446dd1c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -476,6 +476,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (nodes, parenting) = index::index_hir(self.sess, self.resolver.definitions(), node, &bodies); let nodes = hir::OwnerNodes { hash, node_hash, nodes, bodies }; + let attrs = { + let mut hcx = self.resolver.create_stable_hashing_context(); + let mut stable_hasher = StableHasher::new(); + attrs.hash_stable(&mut hcx, &mut stable_hasher); + let hash = stable_hasher.finish(); + hir::AttributeMap { map: attrs, hash } + }; hir::OwnerInfo { nodes, parenting, attrs, trait_map } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4c8157fee3704..bb5c0bc1889bf 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -672,6 +672,23 @@ pub struct ParentedNode<'tcx> { pub node: Node<'tcx>, } +/// Attributes owner by a HIR owner. +#[derive(Debug)] +pub struct AttributeMap<'tcx> { + pub map: BTreeMap, + pub hash: Fingerprint, +} + +impl<'tcx> AttributeMap<'tcx> { + pub const EMPTY: &'static AttributeMap<'static> = + &AttributeMap { map: BTreeMap::new(), hash: Fingerprint::ZERO }; + + #[inline] + pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { + self.map.get(&id).copied().unwrap_or(&[]) + } +} + #[derive(Debug)] pub struct OwnerNodes<'tcx> { /// Pre-computed hash of the full HIR. @@ -691,8 +708,8 @@ pub struct OwnerInfo<'hir> { pub nodes: OwnerNodes<'hir>, /// Map from each nested owner to its parent's local id. pub parenting: FxHashMap, - - pub attrs: BTreeMap, + /// Collected attributes of the HIR nodes. + pub attrs: AttributeMap<'hir>, /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. pub trait_map: FxHashMap>, diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index af8421aeb89a7..93224d388c00f 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -2,6 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html +#![feature(const_btree_new)] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(once_cell)] diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index ad73e363d7f2e..da2aeb9b311bb 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,8 +1,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use crate::hir::{ - BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, OwnerNodes, - TraitItem, TraitItemId, Ty, VisibilityKind, + AttributeMap, BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, + Mod, OwnerNodes, TraitItem, TraitItemId, Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::DefPathHash; @@ -218,3 +218,12 @@ impl HashStable for OwnerNodes<'tcx> { hash.hash_stable(hcx, hasher); } } + +impl HashStable for AttributeMap<'tcx> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + // We ignore the `map` since it refers to information included in `hash` which is hashed in + // the collector and used for the crate hash. + let AttributeMap { hash, map: _ } = *self; + hash.hash_stable(hcx, hasher); + } +} diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 834d5f964e187..af4c0e4843dca 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -580,7 +580,7 @@ impl<'hir> Map<'hir> { let krate = self.krate(); for (owner, info) in krate.owners.iter_enumerated() { if let Some(info) = info { - for (&local_id, attrs) in info.attrs.iter() { + for (&local_id, attrs) in info.attrs.map.iter() { let id = HirId { owner, local_id }; for a in *attrs { visitor.visit_attribute(id, a) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 70179e73b1975..f941981be79b7 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -8,14 +8,12 @@ pub mod place; use crate::ty::query::Providers; use crate::ty::TyCtxt; -use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::LocalDefId; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; use rustc_span::DUMMY_SP; -use std::collections::BTreeMap; /// Top-level HIR node for current owner. This only contains the node for which /// `HirId::local_id == 0`, and excludes bodies. @@ -36,24 +34,6 @@ impl<'a, 'tcx> HashStable> for Owner<'tcx> { } } -/// Attributes owner by a HIR owner. -#[derive(Copy, Clone, Debug, HashStable)] -pub struct AttributeMap<'tcx> { - map: &'tcx BTreeMap, -} - -impl<'tcx> AttributeMap<'tcx> { - fn new(owner_info: &'tcx Option>) -> AttributeMap<'tcx> { - const FALLBACK: &'static BTreeMap = &BTreeMap::new(); - let map = owner_info.as_ref().map_or(FALLBACK, |info| &info.attrs); - AttributeMap { map } - } - - fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { - self.map.get(&id).copied().unwrap_or(&[]) - } -} - /// Gather the LocalDefId for each item-like within a module, including items contained within /// bodies. The Ids are in visitor order. This is used to partition a pass between modules. #[derive(Debug, HashStable)] @@ -105,7 +85,8 @@ pub fn provide(providers: &mut Providers) { }); parent }; - providers.hir_attrs = |tcx, id| AttributeMap::new(&tcx.hir_crate(()).owners[id]); + providers.hir_attrs = + |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map_or(AttributeMap::EMPTY, |o| &o.attrs); providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e7219cc58a18a..e41f5add457fb 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,7 +30,6 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(core_intrinsics)] -#![feature(const_btree_new)] #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e604f59175e8e..eb4cc7c750c11 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -77,7 +77,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_attrs(key: LocalDefId) -> rustc_middle::hir::AttributeMap<'tcx> { + query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> { desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) } } From 0431fdb11312ae324c73e4dab1e5be5c45164678 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 19 Sep 2021 22:07:12 +0200 Subject: [PATCH 10/17] Compute full HIR hash during lowering. --- compiler/rustc_ast_lowering/src/lib.rs | 23 +++++++++- compiler/rustc_hir/src/hir.rs | 3 +- compiler/rustc_hir/src/stable_hash_impls.rs | 18 +++++++- compiler/rustc_middle/src/hir/map/mod.rs | 45 ++++++++----------- compiler/rustc_middle/src/query/mod.rs | 1 - .../rustc_query_system/src/ich/impls_hir.rs | 36 +++++---------- 6 files changed, 69 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9ba3d0446dd1c..84aeb78a0aa10 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -399,6 +399,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::OwnerNode::Crate(lctx.arena.alloc(module)) }); + let hir_hash = self.compute_hir_hash(); + let mut def_id_to_hir_id = IndexVec::default(); for (node_id, hir_id) in self.node_id_to_hir_id.into_iter_enumerated() { @@ -412,10 +414,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id); - let krate = hir::Crate { owners: self.owners }; + let krate = hir::Crate { owners: self.owners, hir_hash }; self.arena.alloc(krate) } + fn compute_hir_hash(&mut self) -> Fingerprint { + let definitions = self.resolver.definitions(); + let mut hir_body_nodes: Vec<_> = self + .owners + .iter_enumerated() + .filter_map(|(def_id, info)| { + let info = info.as_ref()?; + let def_path_hash = definitions.def_path_hash(def_id); + Some((def_path_hash, info)) + }) + .collect(); + hir_body_nodes.sort_unstable_by_key(|bn| bn.0); + + let mut stable_hasher = StableHasher::new(); + let mut hcx = self.resolver.create_stable_hashing_context(); + hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher); + stable_hasher.finish() + } + fn with_hir_id_owner( &mut self, owner: NodeId, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bb5c0bc1889bf..6cbea732c9938 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -702,7 +702,7 @@ pub struct OwnerNodes<'tcx> { pub bodies: IndexVec>>, } -#[derive(Debug)] +#[derive(Debug, HashStable_Generic)] pub struct OwnerInfo<'hir> { /// Contents of the HIR. pub nodes: OwnerNodes<'hir>, @@ -734,6 +734,7 @@ impl<'tcx> OwnerInfo<'tcx> { #[derive(Debug)] pub struct Crate<'hir> { pub owners: IndexVec>>, + pub hir_hash: Fingerprint, } /// A block of statements `{ .. }`, which may have a label (in this case the diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index da2aeb9b311bb..3c9fe93b67d3c 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,8 +1,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use crate::hir::{ - AttributeMap, BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, - Mod, OwnerNodes, TraitItem, TraitItemId, Ty, VisibilityKind, + AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, + ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::DefPathHash; @@ -21,6 +21,7 @@ pub trait HashStableContext: fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher); fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher); fn hash_hir_item_like(&mut self, f: F); + fn hash_hir_trait_candidate(&mut self, _: &TraitCandidate, hasher: &mut StableHasher); } impl ToStableHashKey for HirId { @@ -227,3 +228,16 @@ impl HashStable for AttributeMap<'tcx> hash.hash_stable(hcx, hasher); } } + +impl HashStable for Crate<'_> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + let Crate { owners: _, hir_hash } = self; + hir_hash.hash_stable(hcx, hasher) + } +} + +impl HashStable for TraitCandidate { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + hcx.hash_hir_trait_candidate(self, hasher) + } +} diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index af4c0e4843dca..c8d6ecf6940ed 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1066,18 +1066,8 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { debug_assert_eq!(crate_num, LOCAL_CRATE); - let mut hir_body_nodes: Vec<_> = tcx - .untracked_resolutions - .definitions - .def_path_table() - .all_def_path_hashes_and_def_ids() - .filter_map(|(def_path_hash, local_def_index)| { - let def_id = LocalDefId { local_def_index }; - let hash = tcx.hir_crate(()).owners[def_id].as_ref()?.nodes.hash; - Some((def_path_hash, hash, def_id)) - }) - .collect(); - hir_body_nodes.sort_unstable_by_key(|bn| bn.0); + let krate = tcx.hir_crate(()); + let hir_body_hash = krate.hir_hash; let upstream_crates = upstream_crates(tcx); @@ -1099,22 +1089,25 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { let mut hcx = tcx.create_stable_hashing_context(); let mut stable_hasher = StableHasher::new(); - for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() { - def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher); - fingerprint.hash_stable(&mut hcx, &mut stable_hasher); - tcx.untracked_crate.owners[*def_id] - .as_ref() - .unwrap() - .attrs - .hash_stable(&mut hcx, &mut stable_hasher); - if tcx.sess.opts.debugging_opts.incremental_relative_spans { - let span = tcx.untracked_resolutions.definitions.def_span(*def_id); - debug_assert_eq!(span.parent(), None); - span.hash_stable(&mut hcx, &mut stable_hasher); - } - } + hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher); upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); + if tcx.sess.opts.debugging_opts.incremental_relative_spans { + let definitions = &tcx.untracked_resolutions.definitions; + let mut owner_spans: Vec<_> = krate + .owners + .iter_enumerated() + .filter_map(|(def_id, info)| { + let _ = info.as_ref()?; + let def_path_hash = definitions.def_path_hash(def_id); + let span = definitions.def_span(def_id); + debug_assert_eq!(span.parent(), None); + Some((def_path_hash, span)) + }) + .collect(); + owner_spans.sort_unstable_by_key(|bn| bn.0); + owner_spans.hash_stable(&mut hcx, &mut stable_hasher); + } tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index eb4cc7c750c11..4ffe76fed1c47 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -36,7 +36,6 @@ rustc_queries! { /// prefer wrappers like `tcx.visit_all_items_in_krate()`. query hir_crate(key: ()) -> &'tcx Crate<'tcx> { eval_always - no_hash desc { "get the crate HIR" } } diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs index dc208b36f938e..24f3a2e7de0a9 100644 --- a/compiler/rustc_query_system/src/ich/impls_hir.rs +++ b/compiler/rustc_query_system/src/ich/impls_hir.rs @@ -6,8 +6,6 @@ use crate::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_hir as hir; -use rustc_hir::definitions::DefPathHash; -use smallvec::SmallVec; use std::mem; impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { @@ -121,6 +119,16 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { self.node_id_hashing_mode = prev_hash_node_ids; } + + #[inline] + fn hash_hir_trait_candidate(&mut self, tc: &hir::TraitCandidate, hasher: &mut StableHasher) { + self.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + let hir::TraitCandidate { def_id, import_ids } = tc; + + def_id.hash_stable(hcx, hasher); + import_ids.hash_stable(hcx, hasher); + }); + } } impl<'a> HashStable> for hir::Body<'_> { @@ -135,27 +143,3 @@ impl<'a> HashStable> for hir::Body<'_> { }); } } - -impl<'a> HashStable> for hir::TraitCandidate { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - let hir::TraitCandidate { def_id, import_ids } = self; - - def_id.hash_stable(hcx, hasher); - import_ids.hash_stable(hcx, hasher); - }); - } -} - -impl<'a> ToStableHashKey> for hir::TraitCandidate { - type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>); - - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { - let hir::TraitCandidate { def_id, import_ids } = self; - - ( - hcx.def_path_hash(*def_id), - import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(), - ) - } -} From 04ed86757af86540e5797982f4e70fbf6be24513 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 21 Sep 2021 08:17:18 +0200 Subject: [PATCH 11/17] Bless ui tests. --- src/test/ui/privacy/privacy2.stderr | 8 +------- src/test/ui/privacy/privacy3.stderr | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/test/ui/privacy/privacy2.stderr b/src/test/ui/privacy/privacy2.stderr index 882f314655d83..c2a33ce1f59b3 100644 --- a/src/test/ui/privacy/privacy2.stderr +++ b/src/test/ui/privacy/privacy2.stderr @@ -23,13 +23,7 @@ LL | pub fn foo() {} error: requires `sized` lang_item -error: requires `sized` lang_item - -error: requires `sized` lang_item - -error: requires `sized` lang_item - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0432, E0603. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/privacy/privacy3.stderr b/src/test/ui/privacy/privacy3.stderr index 42ce456d962a1..22c1e48b07d94 100644 --- a/src/test/ui/privacy/privacy3.stderr +++ b/src/test/ui/privacy/privacy3.stderr @@ -6,12 +6,6 @@ LL | use bar::gpriv; error: requires `sized` lang_item -error: requires `sized` lang_item - -error: requires `sized` lang_item - -error: requires `sized` lang_item - -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0432`. From 12b39e59127468b77632cadd2908c7e0f8ed2fea Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 11 Oct 2021 22:36:37 +0200 Subject: [PATCH 12/17] Make naming more explicit. --- compiler/rustc_ast_lowering/src/lib.rs | 16 ++++++++++------ compiler/rustc_hir/src/hir.rs | 6 +++--- compiler/rustc_hir/src/stable_hash_impls.rs | 5 +++-- compiler/rustc_middle/src/hir/mod.rs | 8 ++++---- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 84aeb78a0aa10..19037abdd22e9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -102,7 +102,9 @@ struct LoweringContext<'a, 'hir: 'a> { /// The items being lowered are collected here. owners: IndexVec>>, + /// Bodies inside the owner being lowered. bodies: IndexVec>>, + /// Attributes inside the owner being lowered. attrs: BTreeMap, generator_kind: Option, @@ -418,6 +420,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(krate) } + /// Compute the hash for the HIR of the full crate. + /// This hash will then be part of the crate_hash which is stored in the metadata. fn compute_hir_hash(&mut self) -> Fingerprint { let definitions = self.resolver.definitions(); let mut hir_body_nodes: Vec<_> = self @@ -493,10 +497,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - let (hash, node_hash) = self.hash_body(node, &bodies); + let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies); let (nodes, parenting) = index::index_hir(self.sess, self.resolver.definitions(), node, &bodies); - let nodes = hir::OwnerNodes { hash, node_hash, nodes, bodies }; + let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies }; let attrs = { let mut hcx = self.resolver.create_stable_hashing_context(); let mut stable_hasher = StableHasher::new(); @@ -510,7 +514,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate /// queries which depend on the full HIR tree and those which only depend on the item signature. - fn hash_body( + fn hash_owner( &mut self, node: hir::OwnerNode<'hir>, bodies: &IndexVec>>, @@ -520,13 +524,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| { node.hash_stable(hcx, &mut stable_hasher) }); - let full_hash = stable_hasher.finish(); + let hash_including_bodies = stable_hasher.finish(); let mut stable_hasher = StableHasher::new(); hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| { node.hash_stable(hcx, &mut stable_hasher) }); - let node_hash = stable_hasher.finish(); - (full_hash, node_hash) + let hash_without_bodies = stable_hasher.finish(); + (hash_including_bodies, hash_without_bodies) } /// This method allocates a new `HirId` for the given `NodeId` and stores it in diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6cbea732c9938..0530a69102038 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -692,9 +692,9 @@ impl<'tcx> AttributeMap<'tcx> { #[derive(Debug)] pub struct OwnerNodes<'tcx> { /// Pre-computed hash of the full HIR. - pub hash: Fingerprint, - /// Pre-computed hash of the top node. - pub node_hash: Fingerprint, + pub hash_including_bodies: Fingerprint, + /// Pre-computed hash of the item signature, sithout recursing into the body. + pub hash_without_bodies: Fingerprint, /// Full HIR for the current owner. // The zeroth node's parent is trash, but is never accessed. pub nodes: IndexVec>>, diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 3c9fe93b67d3c..6e7b765a0c441 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -215,8 +215,9 @@ impl HashStable for OwnerNodes<'tcx> { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { // We ignore the `nodes` and `bodies` fields since these refer to information included in // `hash` which is hashed in the collector and used for the crate hash. - let OwnerNodes { hash, node_hash: _, nodes: _, bodies: _ } = *self; - hash.hash_stable(hcx, hasher); + let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } = + *self; + hash_including_bodies.hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index f941981be79b7..1648d0d3ac172 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -23,14 +23,14 @@ use rustc_span::DUMMY_SP; #[derive(Copy, Clone, Debug)] pub struct Owner<'tcx> { node: OwnerNode<'tcx>, - node_hash: Fingerprint, + hash_without_bodies: Fingerprint, } impl<'a, 'tcx> HashStable> for Owner<'tcx> { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Owner { node: _, node_hash } = self; - node_hash.hash_stable(hcx, hasher) + let Owner { node: _, hash_without_bodies } = self; + hash_without_bodies.hash_stable(hcx, hasher) } } @@ -67,7 +67,7 @@ pub fn provide(providers: &mut Providers) { providers.hir_owner = |tcx, id| { let owner = tcx.hir_crate(()).owners[id].as_ref()?; let node = owner.node(); - Some(Owner { node, node_hash: owner.nodes.node_hash }) + Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies }) }; providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes); providers.hir_owner_parent = |tcx, id| { From 6b7995195a7d89ee3d5b669ca7424d0f412ad7bb Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 11 Oct 2021 22:36:46 +0200 Subject: [PATCH 13/17] Remove unused function. --- compiler/rustc_hir/src/definitions.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index b7bdc9a1414ac..ca29351455e62 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -92,12 +92,6 @@ impl DefPathTable { .iter_enumerated() .map(move |(index, key)| (index, key, &self.def_path_hashes[index])) } - - pub fn all_def_path_hashes_and_def_ids( - &self, - ) -> impl Iterator + '_ { - self.def_path_hashes.iter_enumerated().map(move |(index, hash)| (hash, index)) - } } /// The definition table containing node definitions. From c5628a5e656073bd3bceacb7824c2f66845d99f3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 12 Oct 2021 08:34:38 +0200 Subject: [PATCH 14/17] Use invalid local id for zeroth node parent. --- compiler/rustc_ast_lowering/src/index.rs | 5 ++++- compiler/rustc_hir/src/hir.rs | 4 +++- compiler/rustc_hir/src/hir_id.rs | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 7b0f1caaee1e1..dc2b1a730fbd6 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -47,7 +47,10 @@ pub(super) fn index_hir<'hir>( bodies: &IndexVec>>, ) -> (IndexVec>>, FxHashMap) { let mut nodes = IndexVec::new(); - nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: item.into() })); + // This node's parent should never be accessed: the owner's parent is computed by the + // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is + // used. + nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() })); let mut collector = NodeCollector { source_map: sess.source_map(), definitions, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 0530a69102038..1ec37566faba8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -696,7 +696,9 @@ pub struct OwnerNodes<'tcx> { /// Pre-computed hash of the item signature, sithout recursing into the body. pub hash_without_bodies: Fingerprint, /// Full HIR for the current owner. - // The zeroth node's parent is trash, but is never accessed. + // The zeroth node's parent should never be accessed: the owner's parent is computed by the + // hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally + // used. pub nodes: IndexVec>>, /// Content of local bodies. pub bodies: IndexVec>>, diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 0b25ebc27bd3f..877871f7c3d80 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -56,6 +56,10 @@ rustc_index::newtype_index! { pub struct ItemLocalId { .. } } rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId); +impl ItemLocalId { + /// Signal local id which should never be used. + pub const INVALID: ItemLocalId = ItemLocalId::MAX; +} /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`. pub const CRATE_HIR_ID: HirId = HirId { From 7a209bb7a55580076ce77ae859330875f6e2f18c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 12 Oct 2021 20:53:29 +0200 Subject: [PATCH 15/17] Justify untracked access. --- compiler/rustc_middle/src/hir/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 1648d0d3ac172..95d7273b17b44 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -71,6 +71,7 @@ pub fn provide(providers: &mut Providers) { }; providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes); providers.hir_owner_parent = |tcx, id| { + // Accessing the def_key is ok since its value is hashed as part of `id`'s DefPathHash. let parent = tcx.untracked_resolutions.definitions.def_key(id).parent; let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| { let def_id = LocalDefId { local_def_index }; From 394f7198cad038594a9a4e4ed652170d3cdf42f6 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Oct 2021 22:24:43 +0200 Subject: [PATCH 16/17] Allow to hash HIR for coverage. --- compiler/rustc_mir_transform/src/coverage/mod.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 1c946bd2d8af2..e980d3d884f56 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -14,7 +14,6 @@ use spans::{CoverageSpan, CoverageSpans}; use crate::MirPass; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; @@ -29,7 +28,6 @@ use rustc_middle::mir::{ TerminatorKind, }; use rustc_middle::ty::TyCtxt; -use rustc_query_system::ich::StableHashingContext; use rustc_span::def_id::DefId; use rustc_span::source_map::SourceMap; use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol}; @@ -574,15 +572,13 @@ fn get_body_span<'tcx>( } fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 { + // FIXME(cjgillot) Stop hashing HIR manually here. let mut hcx = tcx.create_no_span_stable_hashing_context(); - hash(&mut hcx, &hir_body.value).to_smaller_hash() -} - -fn hash( - hcx: &mut StableHashingContext<'tcx>, - node: &impl HashStable>, -) -> Fingerprint { let mut stable_hasher = StableHasher::new(); - node.hash_stable(hcx, &mut stable_hasher); + let owner = hir_body.id().hir_id.owner; + let bodies = &tcx.hir_owner_nodes(owner).as_ref().unwrap().bodies; + hcx.with_hir_bodies(false, owner, bodies, |hcx| { + hir_body.value.hash_stable(hcx, &mut stable_hasher) + }); stable_hasher.finish() } From 1e2dbb5f4a80077cb4b036b6f4ff96c96ad89805 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 24 Sep 2021 21:15:59 +0200 Subject: [PATCH 17/17] Document structs. --- compiler/rustc_hir/src/hir.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1ec37566faba8..ddda73b91c98f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -672,7 +672,7 @@ pub struct ParentedNode<'tcx> { pub node: Node<'tcx>, } -/// Attributes owner by a HIR owner. +/// Attributes owned by a HIR owner. #[derive(Debug)] pub struct AttributeMap<'tcx> { pub map: BTreeMap, @@ -689,6 +689,9 @@ impl<'tcx> AttributeMap<'tcx> { } } +/// Map of all HIR nodes inside the current owner. +/// These nodes are mapped by `ItemLocalId` alongside the index of their parent node. +/// The HIR tree, including bodies, is pre-hashed. #[derive(Debug)] pub struct OwnerNodes<'tcx> { /// Pre-computed hash of the full HIR. @@ -704,6 +707,7 @@ pub struct OwnerNodes<'tcx> { pub bodies: IndexVec>>, } +/// Full information resulting from lowering an AST node. #[derive(Debug, HashStable_Generic)] pub struct OwnerInfo<'hir> { /// Contents of the HIR.