Skip to content

Commit 6f55015

Browse files
committed
fix "still mutable" ice while metrics are enabled
1 parent e643f59 commit 6f55015

File tree

5 files changed

+120
-5
lines changed

5 files changed

+120
-5
lines changed

compiler/rustc_data_structures/src/sync/freeze.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl<T> FreezeLock<T> {
8888
#[inline]
8989
#[track_caller]
9090
pub fn write(&self) -> FreezeWriteGuard<'_, T> {
91-
self.try_write().expect("still mutable")
91+
self.try_write().expect("data should not be frozen if we're still attempting to mutate it")
9292
}
9393

9494
#[inline]

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,6 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
348348
// Make sure name resolution and macro expansion is run.
349349
let _ = tcx.resolver_for_lowering();
350350

351-
if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
352-
dump_feature_usage_metrics(tcx, metrics_dir);
353-
}
354-
355351
if callbacks.after_expansion(compiler, tcx) == Compilation::Stop {
356352
return early_exit();
357353
}
@@ -370,6 +366,10 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
370366

371367
tcx.ensure_ok().analysis(());
372368

369+
if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
370+
dump_feature_usage_metrics(tcx, metrics_dir);
371+
}
372+
373373
if callbacks.after_analysis(compiler, tcx) == Compilation::Stop {
374374
return early_exit();
375375
}

compiler/rustc_middle/src/query/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,6 +1894,11 @@ rustc_queries! {
18941894

18951895
// The macro which defines `rustc_metadata::provide_extern` depends on this query's name.
18961896
// Changing the name should cause a compiler error, but in case that changes, be aware.
1897+
//
1898+
// The hash should not be calculated before the `analysis` pass is complete, specifically
1899+
// until `tcx.untracked().definitions.freeze()` has been called, otherwise if incremental
1900+
// compilation is enabled calculating this hash can freeze this structure too early in
1901+
// compilation and cause subsequent crashes when attempting to write to `definitions`
18971902
query crate_hash(_: CrateNum) -> Svh {
18981903
eval_always
18991904
desc { "looking up the hash a crate" }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(ascii_char)] // random lib feature
2+
#![feature(box_patterns)] // random lang feature
3+
4+
// picked arbitrary unstable features, just need a random lib and lang feature, ideally ones that
5+
// won't be stabilized any time soon so we don't have to update this test
6+
fn main() {
7+
for s in quix("foo/bar") {
8+
print!("{s}");
9+
}
10+
println!();
11+
}
12+
13+
// need a latebound var to trigger the incremental compilation ICE
14+
fn quix(foo: &str) -> impl Iterator<Item = &'_ str> + '_ {
15+
foo.split('/')
16+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//! This test checks if unstable feature usage metric dump files `unstable-feature-usage*.json` work
2+
//! as expected.
3+
//!
4+
//! - Basic sanity checks on a default ICE dump.
5+
//!
6+
//! See <https://github.com/rust-lang/rust/issues/129485>.
7+
//!
8+
//! # Test history
9+
//!
10+
//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming
11+
//! those will be present in this test as well on the same platform
12+
13+
//@ ignore-windows
14+
//FIXME(#128911): still flakey on i686-mingw.
15+
16+
use std::path::{Path, PathBuf};
17+
18+
use run_make_support::rfs::create_dir_all;
19+
use run_make_support::{
20+
cwd, filename_contains, has_extension, rfs, run_in_tmpdir, rustc, serde_json,
21+
shallow_find_files,
22+
};
23+
24+
fn find_feature_usage_metrics<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> {
25+
shallow_find_files(dir, |path| {
26+
if filename_contains(path, "unstable_feature_usage") && has_extension(path, "json") {
27+
true
28+
} else {
29+
dbg!(path);
30+
false
31+
}
32+
})
33+
}
34+
35+
fn main() {
36+
test_metrics_dump();
37+
test_metrics_errors();
38+
}
39+
40+
#[track_caller]
41+
fn test_metrics_dump() {
42+
run_in_tmpdir(|| {
43+
let metrics_dir = cwd().join("metrics");
44+
create_dir_all(&metrics_dir);
45+
rustc()
46+
.input("main.rs")
47+
.incremental("incremental")
48+
.env("RUST_BACKTRACE", "short")
49+
.arg(format!("-Zmetrics-dir={}", metrics_dir.display()))
50+
.run();
51+
let mut metrics = find_feature_usage_metrics(&metrics_dir);
52+
let json_path =
53+
metrics.pop().expect("there should be one metrics file in the output directory");
54+
55+
// After the `pop` above, there should be no files left.
56+
assert!(
57+
metrics.is_empty(),
58+
"there should be no more than one metrics file in the output directory"
59+
);
60+
61+
let message = rfs::read_to_string(json_path);
62+
let mut parsed: serde_json::Value =
63+
serde_json::from_str(&message).expect("metrics should be dumped as json");
64+
// remove timestamps
65+
assert!(parsed["lib_features"][0]["timestamp"].is_number());
66+
assert!(parsed["lang_features"][0]["timestamp"].is_number());
67+
parsed["lib_features"][0]["timestamp"] = serde_json::json!(null);
68+
parsed["lang_features"][0]["timestamp"] = serde_json::json!(null);
69+
let expected = serde_json::json!(
70+
{
71+
"lib_features":[{"symbol":"ascii_char", "timestamp":null}],
72+
"lang_features":[{"symbol":"box_patterns","since":null, "timestamp":null}]
73+
}
74+
);
75+
76+
assert_eq!(expected, parsed);
77+
});
78+
}
79+
80+
#[track_caller]
81+
fn test_metrics_errors() {
82+
run_in_tmpdir(|| {
83+
rustc()
84+
.input("main.rs")
85+
.incremental("incremental")
86+
.env("RUST_BACKTRACE", "short")
87+
.arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist")
88+
.run_fail()
89+
.assert_stderr_contains(
90+
"error: cannot dump feature usage metrics: No such file or directory",
91+
)
92+
.assert_stdout_not_contains("internal compiler error");
93+
});
94+
}

0 commit comments

Comments
 (0)