Skip to content

Commit

Permalink
Properly handle SyntaxContext of dummy spans in incr comp
Browse files Browse the repository at this point in the history
Fixes #80336

Due to macro expansion, we may end up with spans with an invalid
location and non-root `SyntaxContext`. This commits preserves the
`SyntaxContext` of such spans in the incremental cache, and ensures
that we always hash the `SyntaxContext` when computing the `Fingerprint`
of a `Span`

Previously, we would discard the `SyntaxContext` during serialization to
the incremental cache, causing the span's `Fingerprint` to change across
compilation sessions.
  • Loading branch information
Aaron1011 committed Jan 13, 2021
1 parent fd2df74 commit 482a67d
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 13 deletions.
32 changes: 20 additions & 12 deletions compiler/rustc_middle/src/ty/query/on_disk_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ use std::mem;

const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;

const TAG_VALID_SPAN: u8 = 0;
const TAG_INVALID_SPAN: u8 = 1;
// A normal span encoded with both location information and a `SyntaxContext`
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_SYNTAX_CONTEXT: u8 = 0;
const TAG_EXPN_DATA: u8 = 1;
Expand Down Expand Up @@ -864,10 +866,11 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
let tag: u8 = Decodable::decode(decoder)?;

if tag == TAG_INVALID_SPAN {
return Ok(DUMMY_SP);
if tag == TAG_PARTIAL_SPAN {
let ctxt = SyntaxContext::decode(decoder)?;
return Ok(DUMMY_SP.with_ctxt(ctxt));
} else {
debug_assert_eq!(tag, TAG_VALID_SPAN);
debug_assert_eq!(tag, TAG_FULL_SPAN);
}

let file_lo_index = SourceFileIndex::decode(decoder)?;
Expand Down Expand Up @@ -1057,24 +1060,29 @@ where
{
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
if *self == DUMMY_SP {
return TAG_INVALID_SPAN.encode(s);
TAG_PARTIAL_SPAN.encode(s)?;
return SyntaxContext::root().encode(s);
}

let span_data = self.data();
let (file_lo, line_lo, col_lo) = match s.source_map.byte_pos_to_line_and_col(span_data.lo) {
Some(pos) => pos,
None => return TAG_INVALID_SPAN.encode(s),
let pos = s.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,
};

if !file_lo.contains(span_data.hi) {
return TAG_INVALID_SPAN.encode(s);
if partial_span {
TAG_PARTIAL_SPAN.encode(s)?;
return span_data.ctxt.encode(s);
}

let (file_lo, line_lo, col_lo) = pos.unwrap();

let len = span_data.hi - span_data.lo;

let source_file_index = s.source_file_index(file_lo);

TAG_VALID_SPAN.encode(s)?;
TAG_FULL_SPAN.encode(s)?;
source_file_index.encode(s)?;
line_lo.encode(s)?;
col_lo.encode(s)?;
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1899,8 +1899,9 @@ where
return;
}

if *self == DUMMY_SP {
if self.is_dummy() {
Hash::hash(&TAG_INVALID_SPAN, hasher);
self.ctxt().hash_stable(ctx, hasher);
return;
}

Expand Down
10 changes: 10 additions & 0 deletions src/test/incremental/issue-80336-invalid-span.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Regression test for issue #80336
// Test that we properly handle encoding, decoding, and hashing
// of spans with an invalid location and non-root `SyntaxContext`

// revisions:rpass1 rpass2
// only-x86_64

pub fn main() {
let _ = is_x86_feature_detected!("avx2");
}

0 comments on commit 482a67d

Please sign in to comment.