Skip to content

Commit a895069

Browse files
committed
Include (potentially remapped) working dir in crate hash
Fixes #85019 A `SourceFile` created during compilation may have a relative path (e.g. if rustc itself is invoked with a relative path). When we write out crate metadata, we convert all relative paths to absolute paths using the current working direction. However, the working directory is not included in the crate hash. This means that the crate metadata can change while the crate hash remains the same. Among other problems, this can cause a fingerprint mismatch ICE, since incremental compilation uses the crate metadata hash to determine if a foreign query is green. This commit moves the field holding the working directory from `Session` to `Options`, including it as part of the crate hash.
1 parent c0490a2 commit a895069

File tree

10 files changed

+61
-18
lines changed

10 files changed

+61
-18
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ pub fn file_metadata(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll
771771
let hash = Some(&source_file.src_hash);
772772
let file_name = Some(source_file.name.prefer_remapped().to_string());
773773
let directory = if source_file.is_real_file() && !source_file.is_imported() {
774-
Some(cx.sess().working_dir.to_string_lossy(false).to_string())
774+
Some(cx.sess().opts.working_dir.to_string_lossy(false).to_string())
775775
} else {
776776
// If the path comes from an upstream crate we assume it has been made
777777
// independent of the compiler's working directory one way or another.
@@ -999,7 +999,7 @@ pub fn compile_unit_metadata(
999999
let producer = format!("clang LLVM ({})", rustc_producer);
10001000

10011001
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
1002-
let work_dir = tcx.sess.working_dir.to_string_lossy(false);
1002+
let work_dir = tcx.sess.opts.working_dir.to_string_lossy(false);
10031003
let flags = "\0";
10041004
let output_filenames = tcx.output_filenames(());
10051005
let out_dir = &output_filenames.out_directory;

compiler/rustc_metadata/src/rmeta/encoder.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
503503
// Prepend path of working directory onto potentially
504504
// relative paths, because they could become relative
505505
// to a wrong directory.
506-
let working_dir = &self.tcx.sess.working_dir;
506+
// We include `working_dir` as part of the crate hash,
507+
// so it's okay for us to use it as part of the encoded
508+
// metadata.
509+
let working_dir = &self.tcx.sess.opts.working_dir;
507510
match working_dir {
508511
RealFileName::LocalPath(absolute) => {
509512
// If working_dir has not been remapped, then we emit a

compiler/rustc_save_analysis/src/dump_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ impl<'tcx> DumpVisitor<'tcx> {
185185
};
186186

187187
let data = CompilationOptions {
188-
directory: self.tcx.sess.working_dir.remapped_path_if_available().into(),
188+
directory: self.tcx.sess.opts.working_dir.remapped_path_if_available().into(),
189189
program,
190190
arguments,
191191
output: self.save_ctxt.compilation_output(crate_name),

compiler/rustc_save_analysis/src/span_utils.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ impl<'a> SpanUtils<'a> {
2727
.to_string()
2828
} else {
2929
self.sess
30+
.opts
3031
.working_dir
3132
.remapped_path_if_available()
3233
.join(&path)

compiler/rustc_session/src/config.rs

+17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_feature::UnstableFeatures;
2121
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
2222
use rustc_span::source_map::{FileName, FilePathMapping};
2323
use rustc_span::symbol::{sym, Symbol};
24+
use rustc_span::RealFileName;
2425
use rustc_span::SourceFileHashAlgorithm;
2526

2627
use rustc_errors::emitter::HumanReadableErrorType;
@@ -707,6 +708,7 @@ impl Default for Options {
707708
json_artifact_notifications: false,
708709
json_unused_externs: false,
709710
pretty: None,
711+
working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
710712
}
711713
}
712714
}
@@ -2132,6 +2134,18 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
21322134
if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
21332135
};
21342136

2137+
let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2138+
early_error(error_format, &format!("Current directory is invalid: {}", e));
2139+
});
2140+
2141+
let (path, remapped) =
2142+
FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2143+
let working_dir = if remapped {
2144+
RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2145+
} else {
2146+
RealFileName::LocalPath(path)
2147+
};
2148+
21352149
Options {
21362150
crate_types,
21372151
optimize: opt_level,
@@ -2167,6 +2181,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
21672181
json_artifact_notifications,
21682182
json_unused_externs,
21692183
pretty,
2184+
working_dir,
21702185
}
21712186
}
21722187

@@ -2413,6 +2428,7 @@ crate mod dep_tracking {
24132428
use crate::utils::{NativeLib, NativeLibKind};
24142429
use rustc_feature::UnstableFeatures;
24152430
use rustc_span::edition::Edition;
2431+
use rustc_span::RealFileName;
24162432
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
24172433
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
24182434
use std::collections::hash_map::DefaultHasher;
@@ -2494,6 +2510,7 @@ crate mod dep_tracking {
24942510
TrimmedDefPaths,
24952511
Option<LdImpl>,
24962512
OutputType,
2513+
RealFileName,
24972514
);
24982515

24992516
impl<T1, T2> DepTrackingHash for (T1, T2)

compiler/rustc_session/src/options.rs

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, T
1010

1111
use rustc_feature::UnstableFeatures;
1212
use rustc_span::edition::Edition;
13+
use rustc_span::RealFileName;
1314
use rustc_span::SourceFileHashAlgorithm;
1415

1516
use std::collections::BTreeMap;
@@ -203,6 +204,9 @@ top_level_options!(
203204
json_unused_externs: bool [UNTRACKED],
204205

205206
pretty: Option<PpMode> [UNTRACKED],
207+
208+
/// The (potentially remapped) working directory
209+
working_dir: RealFileName [TRACKED],
206210
}
207211
);
208212

compiler/rustc_session/src/session.rs

+1-14
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use rustc_errors::registry::Registry;
2323
use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorReported};
2424
use rustc_macros::HashStable_Generic;
2525
pub use rustc_span::def_id::StableCrateId;
26+
use rustc_span::edition::Edition;
2627
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
27-
use rustc_span::{edition::Edition, RealFileName};
2828
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
2929
use rustc_target::asm::InlineAsmArch;
3030
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
@@ -139,8 +139,6 @@ pub struct Session {
139139
/// The name of the root source file of the crate, in the local file system.
140140
/// `None` means that there is no source file.
141141
pub local_crate_source_file: Option<PathBuf>,
142-
/// The directory the compiler has been executed in
143-
pub working_dir: RealFileName,
144142

145143
/// Set of `(DiagnosticId, Option<Span>, message)` tuples tracking
146144
/// (sub)diagnostics that have been set once, but should not be set again,
@@ -1304,16 +1302,6 @@ pub fn build_session(
13041302
let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
13051303
let print_fuel = AtomicU64::new(0);
13061304

1307-
let working_dir = env::current_dir().unwrap_or_else(|e| {
1308-
parse_sess.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)).raise()
1309-
});
1310-
let (path, remapped) = file_path_mapping.map_prefix(working_dir.clone());
1311-
let working_dir = if remapped {
1312-
RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
1313-
} else {
1314-
RealFileName::LocalPath(path)
1315-
};
1316-
13171305
let cgu_reuse_tracker = if sopts.debugging_opts.query_dep_graph {
13181306
CguReuseTracker::new()
13191307
} else {
@@ -1344,7 +1332,6 @@ pub fn build_session(
13441332
parse_sess,
13451333
sysroot,
13461334
local_crate_source_file,
1347-
working_dir,
13481335
one_time_diagnostics: Default::default(),
13491336
crate_types: OnceCell::new(),
13501337
stable_crate_id: OnceCell::new(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
include ../../run-make-fulldeps/tools.mk
2+
3+
INCR=$(TMPDIR)/incr
4+
FIRST_SRC=$(TMPDIR)/first_src
5+
SECOND_SRC=$(TMPDIR)/second_src
6+
7+
# Tests that we don't get an ICE when the working directory
8+
# (but not the build directory!) changes between compilation
9+
# sessions
10+
11+
all:
12+
mkdir $(INCR)
13+
# Build from 'FIRST_SRC'
14+
mkdir $(FIRST_SRC)
15+
cp my_lib.rs $(FIRST_SRC)/my_lib.rs
16+
cp main.rs $(FIRST_SRC)/main.rs
17+
cd $(FIRST_SRC) && \
18+
$(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs && \
19+
$(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs
20+
# Build from 'SECOND_SRC', keeping the output directory and incremental directory
21+
# the same
22+
mv $(FIRST_SRC) $(SECOND_SRC)
23+
cd $(SECOND_SRC) && \
24+
$(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs && \
25+
$(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extern crate my_lib;
2+
3+
fn main() {
4+
my_lib::my_fn("hi");
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn my_fn<T: Copy>(_val: T) {}

0 commit comments

Comments
 (0)