1use std::hash::Hash;
2
3use rustc_crate_store::Untracked;
4use rustc_data_structures::fingerprint::Fingerprint;
5use rustc_data_structures::stable_hash::{
6 RawDefId, RawSpan, StableHash, StableHashControls, StableHashCtxt, StableHasher,
7};
8use rustc_data_structures::sync::AppendOnlyIndexVec;
9use rustc_hir::def_id::{DefId, LocalDefId};
10use rustc_session::Session;
11use rustc_span::source_map::SourceMap;
12use rustc_span::{BytePos, CachingSourceMapView, DUMMY_SP, Pos, Span, SpanData};
13
14enum CachingSourceMap<'a> {
17 Unused(&'a SourceMap),
18 InUse(CachingSourceMapView<'a>),
19}
20
21pub struct StableHashState<'a> {
26 untracked: &'a Untracked,
27 incremental_ignore_spans: bool,
30 caching_source_map: CachingSourceMap<'a>,
31 stable_hash_controls: StableHashControls,
32 source_span_cache: SourceSpanCache,
33}
34
35impl<'a> StableHashState<'a> {
36 #[inline]
37 pub fn new(sess: &'a Session, untracked: &'a Untracked) -> Self {
38 let hash_spans_initial = !sess.opts.unstable_opts.incremental_ignore_spans;
39
40 StableHashState {
41 untracked,
42 incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans,
43 caching_source_map: CachingSourceMap::Unused(sess.source_map()),
44 stable_hash_controls: StableHashControls { hash_spans: hash_spans_initial },
45 source_span_cache: SourceSpanCache::default(),
46 }
47 }
48
49 #[inline]
50 pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
51 let prev_hash_spans = self.stable_hash_controls.hash_spans;
52 self.stable_hash_controls.hash_spans = hash_spans;
53 f(self);
54 self.stable_hash_controls.hash_spans = prev_hash_spans;
55 }
56
57 #[inline]
58 fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
59 match self.caching_source_map {
60 CachingSourceMap::InUse(ref mut sm) => sm,
61 CachingSourceMap::Unused(sm) => {
62 self.caching_source_map = CachingSourceMap::InUse(CachingSourceMapView::new(sm));
63 self.source_map() }
65 }
66 }
67
68 #[inline]
69 pub fn stable_hash_controls(&self) -> StableHashControls {
70 self.stable_hash_controls
71 }
72}
73
74impl<'a> StableHashCtxt for StableHashState<'a> {
75 #[inline]
87 fn stable_hash_span(&mut self, raw_span: RawSpan, hasher: &mut StableHasher) {
88 const TAG_VALID_SPAN: u8 = 0;
89 const TAG_INVALID_SPAN: u8 = 1;
90 const TAG_RELATIVE_SPAN: u8 = 2;
91
92 #[inline]
93 fn pack_span_location(
94 line_lo: usize,
95 col_lo: BytePos,
96 line_hi: usize,
97 col_hi: BytePos,
98 ) -> u64 {
99 let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
100 let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
101 let col_hi_trunc = ((col_hi.0 as u64) & 0xFF) << 32;
102 let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
103 col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc
104 }
105
106 if !self.stable_hash_controls().hash_spans {
107 return;
108 }
109
110 let span = Span::from_raw_span(raw_span);
111 let span = span.data_untracked();
112 span.ctxt.stable_hash(self, hasher);
113 span.parent.stable_hash(self, hasher);
114
115 if span.is_dummy() {
116 Hash::hash(&TAG_INVALID_SPAN, hasher);
117 return;
118 }
119
120 let parent = span
121 .parent
122 .map(|parent| self.source_span_cache.lookup(parent, &self.untracked.source_span));
123 if let Some(parent) = parent
124 && parent.contains(span)
125 {
126 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
130 (span.lo - parent.lo).to_u32().stable_hash(self, hasher);
131 (span.hi - parent.lo).to_u32().stable_hash(self, hasher);
132 return;
133 }
134
135 let Some((file, line_lo, col_lo, line_hi, col_hi)) =
138 self.source_map().span_data_to_lines_and_cols(&span)
139 else {
140 Hash::hash(&TAG_INVALID_SPAN, hasher);
141 return;
142 };
143
144 if let Some(parent) = parent
145 && file.contains(parent.lo)
146 {
147 Hash::hash(&TAG_RELATIVE_SPAN, hasher);
150 Hash::hash(&(span.lo.0.wrapping_sub(parent.lo.0)), hasher);
151 Hash::hash(&(span.hi.0.wrapping_sub(parent.lo.0)), hasher);
152 return;
153 }
154
155 Hash::hash(&TAG_VALID_SPAN, hasher);
156 Hash::hash(&file.stable_id, hasher);
157
158 let col_line = pack_span_location(line_lo, col_lo, line_hi, col_hi);
167 let len = (span.hi - span.lo).0;
168 Hash::hash(&col_line, hasher);
169 Hash::hash(&len, hasher);
170 }
171
172 #[inline]
173 fn def_path_hash(&self, raw_def_id: RawDefId) -> Fingerprint {
174 let def_id = DefId::from_raw_def_id(raw_def_id);
175 if let Some(def_id) = def_id.as_local() {
176 self.untracked.definitions.read().def_path_hash(def_id)
177 } else {
178 self.untracked.cstore.read().def_path_hash(def_id)
179 }
180 .0
181 }
182
183 #[inline]
188 fn assert_default_stable_hash_controls(&self, msg: &str) {
189 let stable_hash_controls = self.stable_hash_controls;
190 let StableHashControls { hash_spans } = stable_hash_controls;
191
192 {
match (&hash_spans, &!self.incremental_ignore_spans) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val,
::core::option::Option::Some(format_args!("Attempted hashing of {0} with non-default StableHashControls: {1:?}",
msg, stable_hash_controls)));
}
}
}
};assert_eq!(
200 hash_spans, !self.incremental_ignore_spans,
201 "Attempted hashing of {msg} with non-default StableHashControls: {stable_hash_controls:?}"
202 );
203 }
204
205 #[inline]
206 fn stable_hash_controls(&self) -> StableHashControls {
207 self.stable_hash_controls
208 }
209}
210
211#[derive(#[automatically_derived]
impl ::core::default::Default for SourceSpanCache {
#[inline]
fn default() -> Self {
SourceSpanCache(::core::default::Default::default())
}
}Default)]
218pub(crate) struct SourceSpanCache(Option<(LocalDefId, SpanData)>);
219
220impl SourceSpanCache {
221 #[inline]
222 pub(crate) fn lookup(
223 &mut self,
224 def_id: LocalDefId,
225 source_span: &AppendOnlyIndexVec<LocalDefId, Span>,
226 ) -> SpanData {
227 if let Some(cache) = self.0
228 && cache.0 == def_id
229 {
230 cache.1
231 } else {
232 let span_data = source_span.get(def_id).unwrap_or(DUMMY_SP).data_untracked();
233 self.0 = Some((def_id, span_data));
234 span_data
235 }
236 }
237}