diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index a7ac34428986e..89d7c68a3caee 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -38,6 +38,7 @@ const TAG_FULL_SPAN: u8 = 0; // A partial span with no location information, encoded only with a `SyntaxContext` const TAG_PARTIAL_SPAN: u8 = 1; const TAG_RELATIVE_SPAN: u8 = 2; +const TAG_RELATIVE_OUTER_SPAN: u8 = 3; const TAG_SYNTAX_CONTEXT: u8 = 0; const TAG_EXPN_DATA: u8 = 1; @@ -645,34 +646,41 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { let parent = Option::::decode(self); let tag: u8 = Decodable::decode(self); - if tag == TAG_PARTIAL_SPAN { - return Span::new(BytePos(0), BytePos(0), ctxt, parent); - } else if tag == TAG_RELATIVE_SPAN { - let dlo = u32::decode(self); - let dto = u32::decode(self); - - let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); - let span = Span::new( - enclosing.lo + BytePos::from_u32(dlo), - enclosing.lo + BytePos::from_u32(dto), - ctxt, - parent, - ); - - return span; - } else { - debug_assert_eq!(tag, TAG_FULL_SPAN); - } + let (lo, hi) = match tag { + TAG_PARTIAL_SPAN => (BytePos(0), BytePos(0)), + TAG_RELATIVE_SPAN => { + let dlo = u32::decode(self); + let dto = u32::decode(self); - let file_lo_index = SourceFileIndex::decode(self); - let line_lo = usize::decode(self); - let col_lo = RelativeBytePos::decode(self); - let len = BytePos::decode(self); - - let file_lo = self.file_index_to_file(file_lo_index); - let lo = file_lo.lines()[line_lo - 1] + col_lo; - let lo = file_lo.absolute_position(lo); - let hi = lo + len; + let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); + (enclosing.lo + BytePos::from_u32(dlo), enclosing.lo + BytePos::from_u32(dto)) + } + TAG_RELATIVE_OUTER_SPAN => { + let dlo = isize::decode(self); + let dto = isize::decode(self); + + let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); + let reference = enclosing.lo.to_u32() as isize; + ( + BytePos::from_usize((reference + dlo) as usize), + BytePos::from_usize((reference + dto) as usize), + ) + } + TAG_FULL_SPAN => { + let file_lo_index = SourceFileIndex::decode(self); + let line_lo = usize::decode(self); + let col_lo = RelativeBytePos::decode(self); + let len = BytePos::decode(self); + + let file_lo = self.file_index_to_file(file_lo_index); + let lo = file_lo.lines()[line_lo - 1] + col_lo; + let lo = file_lo.absolute_position(lo); + let hi = lo + len; + + (lo, hi) + } + _ => unreachable!(), + }; Span::new(lo, hi, ctxt, parent) } @@ -897,30 +905,33 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { return TAG_PARTIAL_SPAN.encode(self); } - if let Some(parent) = span_data.parent { - let enclosing = self.tcx.source_span_untracked(parent).data_untracked(); - if enclosing.contains(span_data) { - TAG_RELATIVE_SPAN.encode(self); - (span_data.lo - enclosing.lo).to_u32().encode(self); - (span_data.hi - enclosing.lo).to_u32().encode(self); - return; - } + let parent = + span_data.parent.map(|parent| self.tcx.source_span_untracked(parent).data_untracked()); + if let Some(parent) = parent + && parent.contains(span_data) + { + TAG_RELATIVE_SPAN.encode(self); + (span_data.lo - parent.lo).to_u32().encode(self); + (span_data.hi - parent.lo).to_u32().encode(self); + return; } - let pos = self.source_map.byte_pos_to_line_and_col(span_data.lo); - let partial_span = match &pos { - Some((file_lo, _, _)) => !file_lo.contains(span_data.hi), - None => true, + let Some((file_lo, line_lo, col_lo)) = + self.source_map.byte_pos_to_line_and_col(span_data.lo) + else { + return TAG_PARTIAL_SPAN.encode(self); }; - if partial_span { - return TAG_PARTIAL_SPAN.encode(self); + if let Some(parent) = parent + && file_lo.contains(parent.lo) + { + TAG_RELATIVE_OUTER_SPAN.encode(self); + (span_data.lo.to_u32() as isize - parent.lo.to_u32() as isize).encode(self); + (span_data.hi.to_u32() as isize - parent.lo.to_u32() as isize).encode(self); + return; } - let (file_lo, line_lo, col_lo) = pos.unwrap(); - let len = span_data.hi - span_data.lo; - let source_file_index = self.source_file_index(file_lo); TAG_FULL_SPAN.encode(self); diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index 96d0c02c4a64c..7c720b923a698 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -5,9 +5,7 @@ use rustc_hir::definitions::DefPathHash; use rustc_session::Session; use rustc_session::cstore::Untracked; use rustc_span::source_map::SourceMap; -use rustc_span::{ - BytePos, CachingSourceMapView, DUMMY_SP, Span, SpanData, StableSourceFileId, Symbol, -}; +use rustc_span::{BytePos, CachingSourceMapView, DUMMY_SP, SourceFile, Span, SpanData, Symbol}; use crate::ich; @@ -118,7 +116,7 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { fn span_data_to_lines_and_cols( &mut self, span: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)> { + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)> { self.source_map().span_data_to_lines_and_cols(span) } diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index a887b50ec1ebe..6cf0dbb9f130f 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -2,7 +2,7 @@ use std::ops::Range; use std::sync::Arc; use crate::source_map::SourceMap; -use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData, StableSourceFileId}; +use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData}; #[derive(Clone)] struct CacheEntry { @@ -114,7 +114,7 @@ impl<'sm> CachingSourceMapView<'sm> { pub fn span_data_to_lines_and_cols( &mut self, span_data: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)> { + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)> { self.time_stamp += 1; // Check if lo and hi are in the cached lines. @@ -123,27 +123,25 @@ impl<'sm> CachingSourceMapView<'sm> { if lo_cache_idx != -1 && hi_cache_idx != -1 { // Cache hit for span lo and hi. Check if they belong to the same file. - let result = { - let lo = &self.line_cache[lo_cache_idx as usize]; - let hi = &self.line_cache[hi_cache_idx as usize]; + let lo_file_index = self.line_cache[lo_cache_idx as usize].file_index; + let hi_file_index = self.line_cache[hi_cache_idx as usize].file_index; - if lo.file_index != hi.file_index { - return None; - } - - ( - lo.file.stable_id, - lo.line_number, - span_data.lo - lo.line.start, - hi.line_number, - span_data.hi - hi.line.start, - ) - }; + if lo_file_index != hi_file_index { + return None; + } self.line_cache[lo_cache_idx as usize].touch(self.time_stamp); self.line_cache[hi_cache_idx as usize].touch(self.time_stamp); - return Some(result); + let lo = &self.line_cache[lo_cache_idx as usize]; + let hi = &self.line_cache[hi_cache_idx as usize]; + return Some(( + &*lo.file, + lo.line_number, + span_data.lo - lo.line.start, + hi.line_number, + span_data.hi - hi.line.start, + )); } // No cache hit or cache hit for only one of span lo and hi. @@ -226,7 +224,7 @@ impl<'sm> CachingSourceMapView<'sm> { assert_eq!(lo.file_index, hi.file_index); Some(( - lo.file.stable_id, + &*lo.file, lo.line_number, span_data.lo - lo.line.start, hi.line_number, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9b0e009b2cd37..ea3254934f72b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2623,7 +2623,7 @@ pub trait HashStableContext { fn span_data_to_lines_and_cols( &mut self, span: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)>; + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)>; fn hashing_controls(&self) -> HashingControls; } @@ -2641,6 +2641,7 @@ where /// codepoint offsets. For the purpose of the hash that's sufficient. /// Also, hashing filenames is expensive so we avoid doing it twice when the /// span starts and ends in the same file, which is almost always the case. + // Important: changes to this method should be reflected in implementations of `SpanEncoder`. fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; @@ -2659,15 +2660,15 @@ where return; } - if let Some(parent) = span.parent { - let def_span = ctx.def_span(parent).data_untracked(); - if def_span.contains(span) { - // This span is enclosed in a definition: only hash the relative position. - Hash::hash(&TAG_RELATIVE_SPAN, hasher); - (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher); - (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher); - return; - } + let parent = span.parent.map(|parent| ctx.def_span(parent).data_untracked()); + if let Some(parent) = parent + && parent.contains(span) + { + // This span is enclosed in a definition: only hash the relative position. + Hash::hash(&TAG_RELATIVE_SPAN, hasher); + Hash::hash(&(span.lo - parent.lo), hasher); + Hash::hash(&(span.hi - parent.lo), hasher); + return; } // If this is not an empty or invalid span, we want to hash the last @@ -2680,7 +2681,20 @@ where }; Hash::hash(&TAG_VALID_SPAN, hasher); - Hash::hash(&file, hasher); + Hash::hash(&file.stable_id, hasher); + + if let Some(parent) = parent + && file.contains(parent.lo) + { + // This span is relative to another span in the same file, + // only hash the relative position. + Hash::hash(&TAG_RELATIVE_SPAN, hasher); + // Use signed difference as `span` may start before `parent`, + // for instance attributes start before their item's span. + Hash::hash(&(span.lo.to_u32() as isize - parent.lo.to_u32() as isize), hasher); + Hash::hash(&(span.hi.to_u32() as isize - parent.lo.to_u32() as isize), hasher); + return; + } // Hash both the length and the end location (line/column) of a span. If we // hash only the length, for example, then two otherwise equal spans with