Skip to content

Commit b71e627

Browse files
committed
incr-comp: hash 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 #46744, fix #59954, fix #63161, fix #73640, fix #73967, fix #74890, fix #75900
1 parent 0dce3f6 commit b71e627

File tree

4 files changed

+66
-5
lines changed

4 files changed

+66
-5
lines changed

compiler/rustc_span/src/lib.rs

+26-5
Original file line numberDiff line numberDiff line change
@@ -1878,16 +1878,37 @@ where
18781878
return;
18791879
}
18801880

1881+
let (_, line_hi, col_hi) = match ctx.byte_pos_to_line_and_col(span.hi) {
1882+
Some(pos) => pos,
1883+
None => {
1884+
Hash::hash(&TAG_INVALID_SPAN, hasher);
1885+
span.ctxt.hash_stable(ctx, hasher);
1886+
return;
1887+
}
1888+
};
1889+
18811890
Hash::hash(&TAG_VALID_SPAN, hasher);
18821891
// We truncate the stable ID hash and line and column numbers. The chances
18831892
// of causing a collision this way should be minimal.
18841893
Hash::hash(&(file_lo.name_hash as u64), hasher);
18851894

1886-
let col = (col_lo.0 as u64) & 0xFF;
1887-
let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
1888-
let len = ((span.hi - span.lo).0 as u64) << 32;
1889-
let line_col_len = col | line | len;
1890-
Hash::hash(&line_col_len, hasher);
1895+
// Hash both the length and the end location (line/column) of a span. If we
1896+
// hash only the length, for example, then two otherwise equal spans with
1897+
// different end locations will have the same hash. This can cause a problem
1898+
// during incremental compilation wherein a previous result for a query that
1899+
// depends on the end location of a span will be incorrectly reused when the
1900+
// end location of the span it depends on has changed (see issue #74890). A
1901+
// similar analysis applies if some query depends specifically on the length
1902+
// of the span, but we only hash the end location. So hash both.
1903+
1904+
let col_lo_trunc = (col_lo.0 as u64) & 0xFF;
1905+
let line_lo_trunc = ((line_lo as u64) & 0xFF_FF_FF) << 8;
1906+
let col_hi_trunc = (col_hi.0 as u64) & 0xFF << 32;
1907+
let line_hi_trunc = ((line_hi as u64) & 0xFF_FF_FF) << 40;
1908+
let col_line = col_lo_trunc | line_lo_trunc | col_hi_trunc | line_hi_trunc;
1909+
let len = (span.hi - span.lo).0;
1910+
Hash::hash(&col_line, hasher);
1911+
Hash::hash(&len, hasher);
18911912
span.ctxt.hash_stable(ctx, hasher);
18921913
}
18931914
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-include ../../run-make-fulldeps/tools.mk
2+
3+
# Tests that we don't ICE during incremental compilation after modifying a
4+
# function span such that its previous end line exceeds the number of lines
5+
# in the new file, but its start line/column and length remain the same.
6+
7+
SRC=$(TMPDIR)/src
8+
INCR=$(TMPDIR)/incr
9+
10+
all:
11+
mkdir $(SRC)
12+
mkdir $(INCR)
13+
cp a.rs $(SRC)/main.rs
14+
$(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs
15+
cp b.rs $(SRC)/main.rs
16+
$(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
fn main() {
2+
// foo must be used.
3+
foo();
4+
}
5+
6+
fn foo() {
7+
// foo's span in a.rs and b.rs must be identical
8+
// with respect to start line/column and length.
9+
assert_eq!(1, 1);
10+
11+
12+
13+
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
fn main() {
2+
// foo must be used.
3+
foo();
4+
}
5+
6+
fn foo() {
7+
// foo's span in a.rs and b.rs must be identical
8+
// with respect to start line/column and length.
9+
assert_eq!(1, 1);////
10+
}

0 commit comments

Comments
 (0)