mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-21 12:07:31 +00:00
Auto merge of #76256 - tgnottingham:issue-74890, r=nikomatsakis
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 #46744, fix #59954, fix #63161, fix #73640, fix #73967, fix #74890, fix #75900 --- See #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.
This commit is contained in:
commit
9722952f0b
@ -1894,16 +1894,37 @@ where
|
|||||||
return;
|
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);
|
Hash::hash(&TAG_VALID_SPAN, hasher);
|
||||||
// We truncate the stable ID hash and line and column numbers. The chances
|
// We truncate the stable ID hash and line and column numbers. The chances
|
||||||
// of causing a collision this way should be minimal.
|
// of causing a collision this way should be minimal.
|
||||||
Hash::hash(&(file_lo.name_hash as u64), hasher);
|
Hash::hash(&(file_lo.name_hash as u64), hasher);
|
||||||
|
|
||||||
let col = (col_lo.0 as u64) & 0xFF;
|
// Hash both the length and the end location (line/column) of a span. If we
|
||||||
let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
|
// hash only the length, for example, then two otherwise equal spans with
|
||||||
let len = ((span.hi - span.lo).0 as u64) << 32;
|
// different end locations will have the same hash. This can cause a problem
|
||||||
let line_col_len = col | line | len;
|
// during incremental compilation wherein a previous result for a query that
|
||||||
Hash::hash(&line_col_len, hasher);
|
// 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);
|
span.ctxt.hash_stable(ctx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
src/test/run-make/incr-prev-body-beyond-eof/Makefile
Normal file
19
src/test/run-make/incr-prev-body-beyond-eof/Makefile
Normal file
@ -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
src/test/run-make/incr-prev-body-beyond-eof/a.rs
Normal file
16
src/test/run-make/incr-prev-body-beyond-eof/a.rs
Normal file
@ -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
src/test/run-make/incr-prev-body-beyond-eof/b.rs
Normal file
12
src/test/run-make/incr-prev-body-beyond-eof/b.rs
Normal file
@ -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,5 +1,6 @@
|
|||||||
include ../../run-make-fulldeps/tools.mk
|
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)
|
# ignore-32bit wrong/no cross compiler and sometimes we pass wrong gcc args (-m64)
|
||||||
|
|
||||||
all: foo
|
all: foo
|
||||||
|
Loading…
Reference in New Issue
Block a user