Skip to content

Commit

Permalink
Include (potentially remapped) working dir in crate hash
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Aaron1011 committed Aug 15, 2021
1 parent c0490a2 commit a895069
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 18 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Expand Up @@ -771,7 +771,7 @@ pub fn file_metadata(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll
let hash = Some(&source_file.src_hash);
let file_name = Some(source_file.name.prefer_remapped().to_string());
let directory = if source_file.is_real_file() && !source_file.is_imported() {
Some(cx.sess().working_dir.to_string_lossy(false).to_string())
Some(cx.sess().opts.working_dir.to_string_lossy(false).to_string())
} else {
// If the path comes from an upstream crate we assume it has been made
// independent of the compiler's working directory one way or another.
Expand Down Expand Up @@ -999,7 +999,7 @@ pub fn compile_unit_metadata(
let producer = format!("clang LLVM ({})", rustc_producer);

let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
let work_dir = tcx.sess.working_dir.to_string_lossy(false);
let work_dir = tcx.sess.opts.working_dir.to_string_lossy(false);
let flags = "\0";
let output_filenames = tcx.output_filenames(());
let out_dir = &output_filenames.out_directory;
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Expand Up @@ -503,7 +503,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Prepend path of working directory onto potentially
// relative paths, because they could become relative
// to a wrong directory.
let working_dir = &self.tcx.sess.working_dir;
// We include `working_dir` as part of the crate hash,
// so it's okay for us to use it as part of the encoded
// metadata.
let working_dir = &self.tcx.sess.opts.working_dir;
match working_dir {
RealFileName::LocalPath(absolute) => {
// If working_dir has not been remapped, then we emit a
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_save_analysis/src/dump_visitor.rs
Expand Up @@ -185,7 +185,7 @@ impl<'tcx> DumpVisitor<'tcx> {
};

let data = CompilationOptions {
directory: self.tcx.sess.working_dir.remapped_path_if_available().into(),
directory: self.tcx.sess.opts.working_dir.remapped_path_if_available().into(),
program,
arguments,
output: self.save_ctxt.compilation_output(crate_name),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_save_analysis/src/span_utils.rs
Expand Up @@ -27,6 +27,7 @@ impl<'a> SpanUtils<'a> {
.to_string()
} else {
self.sess
.opts
.working_dir
.remapped_path_if_available()
.join(&path)
Expand Down
17 changes: 17 additions & 0 deletions compiler/rustc_session/src/config.rs
Expand Up @@ -21,6 +21,7 @@ use rustc_feature::UnstableFeatures;
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
use rustc_span::source_map::{FileName, FilePathMapping};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::RealFileName;
use rustc_span::SourceFileHashAlgorithm;

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

let working_dir = std::env::current_dir().unwrap_or_else(|e| {
early_error(error_format, &format!("Current directory is invalid: {}", e));
});

let (path, remapped) =
FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
let working_dir = if remapped {
RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
} else {
RealFileName::LocalPath(path)
};

Options {
crate_types,
optimize: opt_level,
Expand Down Expand Up @@ -2167,6 +2181,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
json_artifact_notifications,
json_unused_externs,
pretty,
working_dir,
}
}

Expand Down Expand Up @@ -2413,6 +2428,7 @@ crate mod dep_tracking {
use crate::utils::{NativeLib, NativeLibKind};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_span::RealFileName;
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
use std::collections::hash_map::DefaultHasher;
Expand Down Expand Up @@ -2494,6 +2510,7 @@ crate mod dep_tracking {
TrimmedDefPaths,
Option<LdImpl>,
OutputType,
RealFileName,
);

impl<T1, T2> DepTrackingHash for (T1, T2)
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_session/src/options.rs
Expand Up @@ -10,6 +10,7 @@ use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, T

use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_span::RealFileName;
use rustc_span::SourceFileHashAlgorithm;

use std::collections::BTreeMap;
Expand Down Expand Up @@ -203,6 +204,9 @@ top_level_options!(
json_unused_externs: bool [UNTRACKED],

pretty: Option<PpMode> [UNTRACKED],

/// The (potentially remapped) working directory
working_dir: RealFileName [TRACKED],
}
);

Expand Down
15 changes: 1 addition & 14 deletions compiler/rustc_session/src/session.rs
Expand Up @@ -23,8 +23,8 @@ use rustc_errors::registry::Registry;
use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorReported};
use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
use rustc_span::edition::Edition;
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
use rustc_span::{edition::Edition, RealFileName};
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
Expand Down Expand Up @@ -139,8 +139,6 @@ pub struct Session {
/// The name of the root source file of the crate, in the local file system.
/// `None` means that there is no source file.
pub local_crate_source_file: Option<PathBuf>,
/// The directory the compiler has been executed in
pub working_dir: RealFileName,

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

let working_dir = env::current_dir().unwrap_or_else(|e| {
parse_sess.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)).raise()
});
let (path, remapped) = file_path_mapping.map_prefix(working_dir.clone());
let working_dir = if remapped {
RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
} else {
RealFileName::LocalPath(path)
};

let cgu_reuse_tracker = if sopts.debugging_opts.query_dep_graph {
CguReuseTracker::new()
} else {
Expand Down Expand Up @@ -1344,7 +1332,6 @@ pub fn build_session(
parse_sess,
sysroot,
local_crate_source_file,
working_dir,
one_time_diagnostics: Default::default(),
crate_types: OnceCell::new(),
stable_crate_id: OnceCell::new(),
Expand Down
25 changes: 25 additions & 0 deletions src/test/run-make/issue-85019-moved-src-dir/Makefile
@@ -0,0 +1,25 @@
include ../../run-make-fulldeps/tools.mk

INCR=$(TMPDIR)/incr
FIRST_SRC=$(TMPDIR)/first_src
SECOND_SRC=$(TMPDIR)/second_src

# Tests that we don't get an ICE when the working directory
# (but not the build directory!) changes between compilation
# sessions

all:
mkdir $(INCR)
# Build from 'FIRST_SRC'
mkdir $(FIRST_SRC)
cp my_lib.rs $(FIRST_SRC)/my_lib.rs
cp main.rs $(FIRST_SRC)/main.rs
cd $(FIRST_SRC) && \
$(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs && \
$(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs
# Build from 'SECOND_SRC', keeping the output directory and incremental directory
# the same
mv $(FIRST_SRC) $(SECOND_SRC)
cd $(SECOND_SRC) && \
$(RUSTC) -C incremental=$(INCR) --crate-type lib my_lib.rs && \
$(RUSTC) -C incremental=$(INCR) --extern my_lib=$(TMPDIR)/libmy_lib.rlib main.rs
5 changes: 5 additions & 0 deletions src/test/run-make/issue-85019-moved-src-dir/main.rs
@@ -0,0 +1,5 @@
extern crate my_lib;

fn main() {
my_lib::my_fn("hi");
}
1 change: 1 addition & 0 deletions src/test/run-make/issue-85019-moved-src-dir/my_lib.rs
@@ -0,0 +1 @@
pub fn my_fn<T: Copy>(_val: T) {}

0 comments on commit a895069

Please sign in to comment.