Skip to content

Commit d922092

Browse files
committed
Import SourceFiles from crate before decoding foreign Span
Fixes #92163 Fixes #92014 When writing to the incremental cache, we encode all `Span`s we encounter, regardless of whether or not their `SourceFile` comes from the local crate, or from a foreign crate. When we decode a `Span`, we use the `StableSourceFileId` we encoded to locate the matching `SourceFile` in the current session. If this id corresponds to a `SourceFile` from another crate, then we need to have already imported that `SourceFile` into our current session. This usually happens automatically during resolution / macro expansion, when we try to resolve definitions from other crates. In certain cases, however, we may try to load a `Span` from a transitive dependency without having ever imported the `SourceFile`s from that crate, leading to an ICE. This PR fixes the issue by calling `imported_source_files()` when we encounter a `SourceFile` with a foreign `CrateNum`. This ensures that all `SourceFile`s from that crate are imported into the current session.
1 parent 489296d commit d922092

File tree

6 files changed

+68
-0
lines changed

6 files changed

+68
-0
lines changed

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+4
Original file line numberDiff line numberDiff line change
@@ -536,4 +536,8 @@ impl CrateStore for CStore {
536536
) -> ExpnId {
537537
self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash)
538538
}
539+
540+
fn import_source_files(&self, sess: &Session, cnum: CrateNum) {
541+
self.get_crate_data(cnum).imported_source_files(sess);
542+
}
539543
}

compiler/rustc_query_impl/src/on_disk_cache.rs

+14
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,20 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
495495
.entry(index)
496496
.or_insert_with(|| {
497497
let stable_id = file_index_to_stable_id[&index].translate(tcx);
498+
499+
// If this `SourceFile` is from a foreign crate, then make sure
500+
// that we've imported all of the source files from that crate.
501+
// This has usually already been done during macro invocation.
502+
// However, when encoding query results like `TypeckResults`,
503+
// we might encode an `AdtDef` for a foreign type (because it
504+
// was referenced in the body of the function). There is no guarantee
505+
// that we will load the source files from that crate during macro
506+
// expansion, so we use `import_source_files` to ensure that the foreign
507+
// source files are actually imported before we call `source_file_by_stable_id`.
508+
if stable_id.cnum != LOCAL_CRATE {
509+
self.tcx.cstore_untracked().import_source_files(self.tcx.sess, stable_id.cnum);
510+
}
511+
498512
source_map
499513
.source_file_by_stable_id(stable_id)
500514
.expect("failed to lookup `SourceFile` in new context")

compiler/rustc_session/src/cstore.rs

+6
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ pub trait CrateStore: std::fmt::Debug {
201201
index_guess: u32,
202202
hash: ExpnHash,
203203
) -> ExpnId;
204+
205+
/// Imports all `SourceFile`s from the given crate into the current session.
206+
/// This normally happens automatically when we decode a `Span` from
207+
/// that crate's metadata - however, the incr comp cache needs
208+
/// to trigger this manually when decoding a foreign `Span`
209+
fn import_source_files(&self, sess: &Session, cnum: CrateNum);
204210
}
205211

206212
pub type CrateStoreDyn = dyn CrateStore + sync::Sync;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub enum Foo {
2+
Variant
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags:--extern first_crate
2+
3+
// Note: adding `first_crate` to the extern prelude
4+
// (instead of using `extern_crate`) appears to be necessary to
5+
// trigger the original incremental compilation bug.
6+
// I'm not entirely sure why this is the case
7+
8+
pub fn make_it() -> first_crate::Foo {
9+
panic!()
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// aux-build:first_crate.rs
2+
// aux-build:second_crate.rs
3+
// revisions:rpass1 rpass2
4+
5+
// Regression test for issue #92163
6+
// Under certain circumstances, we may end up trying to
7+
// decode a foreign `Span` from the incremental cache, without previously
8+
// having imported the `SourceFile`s from the owning crate. This can happen
9+
// if the `Span` comes from a transitive dependency (so we never try to resolve
10+
// items from the crate during expansion/resolution).
11+
//
12+
// Previously, this would result in an ICE, since we would not have loaded
13+
// the corresponding `SourceFile` for the `StableSourceFileId` we decoded.
14+
// This test verifies that the decoding of a foreign `Span` will always
15+
// try to import the `SourceFile`s from the foreign crate, instead of
16+
// relying on that having already happened during expansion.
17+
18+
extern crate second_crate;
19+
20+
pub struct Outer;
21+
22+
impl Outer {
23+
pub fn use_it() {
24+
// This returns `first_crate::Foo`, causing
25+
// us to encode the `AdtDef `first_crate::Foo` (along with its `Span`s)
26+
// into the query cache for the `TypeckResults` for this function.
27+
second_crate::make_it();
28+
}
29+
}
30+
31+
fn main() {}

0 commit comments

Comments
 (0)