]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_query_system/src/ich/hcx.rs
Forbid hashing HIR outside of indexing.
[rust.git] / compiler / rustc_query_system / src / ich / hcx.rs
1 use crate::ich;
2 use rustc_ast as ast;
3 use rustc_data_structures::fx::FxHashSet;
4 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5 use rustc_data_structures::sync::Lrc;
6 use rustc_hir as hir;
7 use rustc_hir::def_id::{DefId, LocalDefId};
8 use rustc_hir::definitions::{DefPathHash, Definitions};
9 use rustc_index::vec::IndexVec;
10 use rustc_session::cstore::CrateStore;
11 use rustc_session::Session;
12 use rustc_span::source_map::SourceMap;
13 use rustc_span::symbol::Symbol;
14 use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData};
15
16 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
17     debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
18     ich::IGNORED_ATTRIBUTES.iter().copied().collect()
19 }
20
21 /// This is the context state available during incr. comp. hashing. It contains
22 /// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
23 /// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
24 /// things (e.g., each `DefId`/`DefPath` is only hashed once).
25 #[derive(Clone)]
26 pub struct StableHashingContext<'a> {
27     definitions: &'a Definitions,
28     cstore: &'a dyn CrateStore,
29     pub(super) body_resolver: BodyResolver<'a>,
30     hash_spans: bool,
31     pub(super) node_id_hashing_mode: NodeIdHashingMode,
32
33     // Very often, we are hashing something that does not need the
34     // `CachingSourceMapView`, so we initialize it lazily.
35     raw_source_map: &'a SourceMap,
36     caching_source_map: Option<CachingSourceMapView<'a>>,
37 }
38
39 #[derive(PartialEq, Eq, Clone, Copy)]
40 pub enum NodeIdHashingMode {
41     Ignore,
42     HashDefPath,
43 }
44
45 /// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
46 /// We could also just store a plain reference to the `hir::Crate` but we want
47 /// to avoid that the crate is used to get untracked access to all of the HIR.
48 #[derive(Clone, Copy)]
49 pub(super) enum BodyResolver<'tcx> {
50     Forbidden,
51     Traverse {
52         hash_bodies: bool,
53         owner: LocalDefId,
54         bodies: &'tcx IndexVec<hir::ItemLocalId, Option<&'tcx hir::Body<'tcx>>>,
55     },
56 }
57
58 impl<'a> StableHashingContext<'a> {
59     #[inline]
60     fn new_with_or_without_spans(
61         sess: &'a Session,
62         definitions: &'a Definitions,
63         cstore: &'a dyn CrateStore,
64         always_ignore_spans: bool,
65     ) -> Self {
66         let hash_spans_initial =
67             !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
68
69         StableHashingContext {
70             body_resolver: BodyResolver::Forbidden,
71             definitions,
72             cstore,
73             caching_source_map: None,
74             raw_source_map: sess.source_map(),
75             hash_spans: hash_spans_initial,
76             node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
77         }
78     }
79
80     #[inline]
81     pub fn new(
82         sess: &'a Session,
83         definitions: &'a Definitions,
84         cstore: &'a dyn CrateStore,
85     ) -> Self {
86         Self::new_with_or_without_spans(
87             sess,
88             definitions,
89             cstore,
90             /*always_ignore_spans=*/ false,
91         )
92     }
93
94     #[inline]
95     pub fn ignore_spans(
96         sess: &'a Session,
97         definitions: &'a Definitions,
98         cstore: &'a dyn CrateStore,
99     ) -> Self {
100         let always_ignore_spans = true;
101         Self::new_with_or_without_spans(sess, definitions, cstore, always_ignore_spans)
102     }
103
104     /// Allow hashing
105     #[inline]
106     pub fn while_hashing_hir_bodies(&mut self, hb: bool, f: impl FnOnce(&mut Self)) {
107         let prev = match &mut self.body_resolver {
108             BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."),
109             BodyResolver::Traverse { ref mut hash_bodies, .. } => {
110                 std::mem::replace(hash_bodies, hb)
111             }
112         };
113         f(self);
114         match &mut self.body_resolver {
115             BodyResolver::Forbidden => unreachable!(),
116             BodyResolver::Traverse { ref mut hash_bodies, .. } => *hash_bodies = prev,
117         }
118     }
119
120     #[inline]
121     pub fn with_hir_bodies(
122         &mut self,
123         hash_bodies: bool,
124         owner: LocalDefId,
125         bodies: &'a IndexVec<hir::ItemLocalId, Option<&'a hir::Body<'a>>>,
126         f: impl FnOnce(&mut Self),
127     ) {
128         let prev = self.body_resolver;
129         self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies };
130         f(self);
131         self.body_resolver = prev;
132     }
133
134     #[inline]
135     pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
136         let prev_hash_spans = self.hash_spans;
137         self.hash_spans = hash_spans;
138         f(self);
139         self.hash_spans = prev_hash_spans;
140     }
141
142     #[inline]
143     pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
144         &mut self,
145         mode: NodeIdHashingMode,
146         f: F,
147     ) {
148         let prev = self.node_id_hashing_mode;
149         self.node_id_hashing_mode = mode;
150         f(self);
151         self.node_id_hashing_mode = prev;
152     }
153
154     #[inline]
155     pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
156         if let Some(def_id) = def_id.as_local() {
157             self.local_def_path_hash(def_id)
158         } else {
159             self.cstore.def_path_hash(def_id)
160         }
161     }
162
163     #[inline]
164     pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
165         self.definitions.def_path_hash(def_id)
166     }
167
168     #[inline]
169     pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
170         match self.caching_source_map {
171             Some(ref mut sm) => sm,
172             ref mut none => {
173                 *none = Some(CachingSourceMapView::new(self.raw_source_map));
174                 none.as_mut().unwrap()
175             }
176         }
177     }
178
179     #[inline]
180     pub fn is_ignored_attr(&self, name: Symbol) -> bool {
181         thread_local! {
182             static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
183         }
184         IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
185     }
186 }
187
188 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
189     #[inline]
190     fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
191         panic!("Node IDs should not appear in incremental state");
192     }
193 }
194
195 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
196     #[inline]
197     fn hash_spans(&self) -> bool {
198         self.hash_spans
199     }
200
201     #[inline]
202     fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
203         self.def_path_hash(def_id)
204     }
205
206     #[inline]
207     fn def_span(&self, def_id: LocalDefId) -> Span {
208         self.definitions.def_span(def_id)
209     }
210
211     #[inline]
212     fn span_data_to_lines_and_cols(
213         &mut self,
214         span: &SpanData,
215     ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
216         self.source_map().span_data_to_lines_and_cols(span)
217     }
218 }
219
220 impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}