Skip to content

Commit

Permalink
Auto merge of rust-lang#76256 - tgnottingham:issue-74890, r=nikomatsakis
Browse files Browse the repository at this point in the history
incr-comp: hash and serialize span end line/column

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
different end locations will have the same hash. This can cause a
problem during incremental compilation wherein a previous result for a
query that depends on the end location of a span will be incorrectly
reused when the end location of the span it depends on has changed. A
similar analysis applies if some query depends specifically on the
length of the span, but we only hash the end location. So hash both.

Fix rust-lang#46744, fix rust-lang#59954, fix rust-lang#63161, fix rust-lang#73640, fix rust-lang#73967, fix rust-lang#74890, fix rust-lang#75900

---

See rust-lang#74890 for a more in-depth analysis.

I haven't thought about what other problems this root cause could be responsible for. Please let me know if anything springs to mind. I believe the issue has existed since the inception of incremental compilation.
  • Loading branch information
bors committed Nov 12, 2020
2 parents 7f5a42b + dac57e6 commit 9722952
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 5 deletions.
31 changes: 26 additions & 5 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1894,16 +1894,37 @@ where
return;
}

let (_, line_hi, col_hi) = match ctx.byte_pos_to_line_and_col(span.hi) {
Some(pos) => pos,
None => {
Hash::hash(&TAG_INVALID_SPAN, hasher);
span.ctxt.hash_stable(ctx, hasher);
return;
}
};

Hash::hash(&TAG_VALID_SPAN, hasher);
// We truncate the stable ID hash and line and column numbers. The chances
// of causing a collision this way should be minimal.
Hash::hash(&(file_lo.name_hash as u64), hasher);

let col = (col_lo.0 as u64) & 0xFF;
let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
let len = ((span.hi - span.lo).0 as u64) << 32;
let line_col_len = col | line | len;
Hash::hash(&line_col_len, hasher);
// 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
// different end locations will have the same hash. This can cause a problem
// during incremental compilation wherein a previous result for a query that
// depends on the end location of a span will be incorrectly reused when the
// end location of the span it depends on has changed (see issue #74890). A
// similar analysis applies if some query depends specifically on the length
// of the span, but we only hash the end location. So hash both.

let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
let len = (span.hi - span.lo).0;
Hash::hash(&col_line, hasher);
Hash::hash(&len, hasher);
span.ctxt.hash_stable(ctx, hasher);
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/test/run-make/incr-prev-body-beyond-eof/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
include ../../run-make-fulldeps/tools.mk

# FIXME https://github.com/rust-lang/rust/issues/78911
# ignore-32bit wrong/no cross compiler and sometimes we pass wrong gcc args (-m64)

# Tests that we don't ICE during incremental compilation after modifying a
# function span such that its previous end line exceeds the number of lines
# in the new file, but its start line/column and length remain the same.

SRC=$(TMPDIR)/src
INCR=$(TMPDIR)/incr

all:
mkdir $(SRC)
mkdir $(INCR)
cp a.rs $(SRC)/main.rs
$(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs
cp b.rs $(SRC)/main.rs
$(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs
16 changes: 16 additions & 0 deletions src/test/run-make/incr-prev-body-beyond-eof/a.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
fn main() {
// foo must be used.
foo();
}

// For this test to operate correctly, foo's body must start on exactly the same
// line and column and have the exact same length in bytes in a.rs and b.rs. In
// a.rs, the body must end on a line number which does not exist in b.rs.
// Basically, avoid modifying this file, including adding or removing whitespace!
fn foo() {
assert_eq!(1, 1);




}
12 changes: 12 additions & 0 deletions src/test/run-make/incr-prev-body-beyond-eof/b.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn main() {
// foo must be used.
foo();
}

// For this test to operate correctly, foo's body must start on exactly the same
// line and column and have the exact same length in bytes in a.rs and b.rs. In
// a.rs, the body must end on a line number which does not exist in b.rs.
// Basically, avoid modifying this file, including adding or removing whitespace!
fn foo() {
assert_eq!(1, 1);////
}
1 change: 1 addition & 0 deletions src/test/run-make/issue-36710/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include ../../run-make-fulldeps/tools.mk

# FIXME https://github.com/rust-lang/rust/issues/78911
# ignore-32bit wrong/no cross compiler and sometimes we pass wrong gcc args (-m64)

all: foo
Expand Down

0 comments on commit 9722952

Please sign in to comment.