Skip to content

Commit 5f274b0

Browse files
committed
Show information about abnormal fix errors.
1 parent 649822b commit 5f274b0

File tree

3 files changed

+105
-4
lines changed

3 files changed

+105
-4
lines changed

src/cargo/ops/fix.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use std::process::{self, Command, ExitStatus};
4646
use std::str;
4747

4848
use anyhow::{bail, Context, Error};
49-
use cargo_util::{paths, ProcessBuilder};
49+
use cargo_util::{exit_status_to_string, is_simple_exit_code, paths, ProcessBuilder};
5050
use log::{debug, trace, warn};
5151
use rustfix::diagnostics::Diagnostic;
5252
use rustfix::{self, CodeFix};
@@ -374,7 +374,7 @@ pub fn fix_maybe_exec_rustc(config: &Config) -> CargoResult<bool> {
374374
paths::write(path, &file.original_code)?;
375375
}
376376
}
377-
log_failed_fix(&output.stderr)?;
377+
log_failed_fix(&output.stderr, output.status)?;
378378
}
379379
}
380380

@@ -662,7 +662,7 @@ fn exit_with(status: ExitStatus) -> ! {
662662
process::exit(status.code().unwrap_or(3));
663663
}
664664

665-
fn log_failed_fix(stderr: &[u8]) -> Result<(), Error> {
665+
fn log_failed_fix(stderr: &[u8], status: ExitStatus) -> Result<(), Error> {
666666
let stderr = str::from_utf8(stderr).context("failed to parse rustc stderr as utf-8")?;
667667

668668
let diagnostics = stderr
@@ -677,6 +677,13 @@ fn log_failed_fix(stderr: &[u8]) -> Result<(), Error> {
677677
files.insert(span.file_name);
678678
}
679679
}
680+
// Include any abnormal messages (like an ICE or whatever).
681+
errors.extend(
682+
stderr
683+
.lines()
684+
.filter(|x| !x.starts_with('{'))
685+
.map(|x| x.to_string()),
686+
);
680687
let mut krate = None;
681688
let mut prev_dash_dash_krate_name = false;
682689
for arg in env::args() {
@@ -692,10 +699,16 @@ fn log_failed_fix(stderr: &[u8]) -> Result<(), Error> {
692699
}
693700

694701
let files = files.into_iter().collect();
702+
let abnormal_exit = if status.code().map_or(false, is_simple_exit_code) {
703+
None
704+
} else {
705+
Some(exit_status_to_string(status))
706+
};
695707
Message::FixFailed {
696708
files,
697709
krate,
698710
errors,
711+
abnormal_exit,
699712
}
700713
.post()?;
701714

src/cargo/util/diagnostic_server.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub enum Message {
4848
files: Vec<String>,
4949
krate: Option<String>,
5050
errors: Vec<String>,
51+
abnormal_exit: Option<String>,
5152
},
5253
ReplaceFailed {
5354
file: String,
@@ -135,6 +136,7 @@ impl<'a> DiagnosticPrinter<'a> {
135136
files,
136137
krate,
137138
errors,
139+
abnormal_exit,
138140
} => {
139141
if let Some(ref krate) = *krate {
140142
self.config.shell().warn(&format!(
@@ -171,6 +173,13 @@ impl<'a> DiagnosticPrinter<'a> {
171173
}
172174
}
173175
}
176+
if let Some(exit) = abnormal_exit {
177+
writeln!(
178+
self.config.shell().err(),
179+
"rustc exited abnormally: {}",
180+
exit
181+
)?;
182+
}
174183
writeln!(
175184
self.config.shell().err(),
176185
"Original diagnostics will follow.\n"

tests/testsuite/fix.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use cargo::core::Edition;
44
use cargo_test_support::compare::assert_match_exact;
55
use cargo_test_support::git;
6-
use cargo_test_support::paths::CargoPathExt;
6+
use cargo_test_support::paths::{self, CargoPathExt};
77
use cargo_test_support::registry::{Dependency, Package};
88
use cargo_test_support::tools;
99
use cargo_test_support::{basic_manifest, is_nightly, project};
@@ -1597,3 +1597,82 @@ fn fix_shared_cross_workspace() {
15971597
&p.read_file("foo/src/shared.rs"),
15981598
);
15991599
}
1600+
1601+
#[cargo_test]
1602+
fn abnormal_exit() {
1603+
// rustc fails unexpectedly after applying fixes, should show some error information.
1604+
//
1605+
// This works with a proc-macro that runs three times:
1606+
// - First run (collect diagnostics pass): writes a file, exits normally.
1607+
// - Second run (verify diagnostics work): it detects the presence of the
1608+
// file, removes the file, and aborts the process.
1609+
// - Third run (collecting messages to display): file not found, exits normally.
1610+
let p = project()
1611+
.file(
1612+
"Cargo.toml",
1613+
r#"
1614+
[package]
1615+
name = "foo"
1616+
version = "0.1.0"
1617+
1618+
[dependencies]
1619+
pm = {path="pm"}
1620+
"#,
1621+
)
1622+
.file(
1623+
"src/lib.rs",
1624+
r#"
1625+
pub fn f() {
1626+
let mut x = 1;
1627+
pm::crashme!();
1628+
}
1629+
"#,
1630+
)
1631+
.file(
1632+
"pm/Cargo.toml",
1633+
r#"
1634+
[package]
1635+
name = "pm"
1636+
version = "0.1.0"
1637+
edition = "2018"
1638+
1639+
[lib]
1640+
proc-macro = true
1641+
"#,
1642+
)
1643+
.file(
1644+
"pm/src/lib.rs",
1645+
r#"
1646+
use proc_macro::TokenStream;
1647+
#[proc_macro]
1648+
pub fn crashme(_input: TokenStream) -> TokenStream {
1649+
// Use a file to succeed on the first pass, and fail on the second.
1650+
let p = std::env::var_os("ONCE_PATH").unwrap();
1651+
let check_path = std::path::Path::new(&p);
1652+
if check_path.exists() {
1653+
eprintln!("I'm not a diagnostic.");
1654+
std::fs::remove_file(check_path).unwrap();
1655+
std::process::abort();
1656+
} else {
1657+
std::fs::write(check_path, "").unwrap();
1658+
"".parse().unwrap()
1659+
}
1660+
}
1661+
"#,
1662+
)
1663+
.build();
1664+
1665+
p.cargo("fix --lib --allow-no-vcs")
1666+
.env(
1667+
"ONCE_PATH",
1668+
paths::root().join("proc-macro-run-once").to_str().unwrap(),
1669+
)
1670+
.with_stderr_contains(
1671+
"[WARNING] failed to automatically apply fixes suggested by rustc to crate `foo`",
1672+
)
1673+
.with_stderr_contains("I'm not a diagnostic.")
1674+
// "signal: 6, SIGABRT: process abort signal" on some platforms
1675+
.with_stderr_contains("rustc exited abnormally: [..]")
1676+
.with_stderr_contains("Original diagnostics will follow.")
1677+
.run();
1678+
}

0 commit comments

Comments
 (0)