Skip to content

Commit cc80b40

Browse files
committed
Auto merge of #9655 - jyn514:verbose, r=ehuss
Unify cargo and rustc's error reporting Fixes rust-lang/rust#86854. ## Don't print "run the command again with --verbose" Here is a typical error seen by users of Cargo: ``` error[E0601]: `main` function not found in crate `wrong` | = note: consider adding a `main` function to `src/main.rs` error: aborting due to previous error For more information about this error, try `rustc --explain E0601`. error: could not compile `wrong` To learn more, run the command again with --verbose. ``` The `--verbose` output is not particularly helpful in this case. The error is unrelated to what cargo is doing, and passing `--verbose` will not give useful information about how to proceed. Additionally, it's unclear that `--verbose` is referring to the cargo command and not rustc; this is especially true when cargo is wrapped by another build system (such as Meson, x.py, or Make). This omits the "run the command again with --verbose" output. --verbose is still shown in `cargo build --help`, but it's not singled out above all the other options. ## Combine rustc and cargo's diagnostic summaries This works by introspecting rustc's error output, using the JSON format to determine whether it's a warning or error, then skipping it altogether if it's a summary of the diagnostics printed. Before: ``` $ cargo check --message-format short src/main.rs:1:10: warning: trait objects without an explicit `dyn` are deprecated src/main.rs:1:1: error[E0601]: `main` function not found in crate `wrong` src/main.rs:1:9: error[E0038]: the trait `Clone` cannot be made into an object error: aborting due to 2 previous errors; 1 warning emitted error: could not compile `wrong` ``` After: ``` $ cargo check --message-format short src/main.rs:1:10: warning: trait objects without an explicit `dyn` are deprecated src/main.rs:1:1: error[E0601]: `main` function not found in crate `wrong` src/main.rs:1:9: error[E0038]: the trait `Clone` cannot be made into an object error: could not compile `wrong` due to 2 previous errors; 1 warning emitted ```
2 parents 3ebb5f1 + 9c7cc54 commit cc80b40

File tree

8 files changed

+53
-23
lines changed

8 files changed

+53
-23
lines changed

src/cargo/core/compiler/future_incompat.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub struct FutureBreakageItem {
5151
#[derive(Serialize, Deserialize)]
5252
pub struct Diagnostic {
5353
pub rendered: String,
54+
pub level: String,
5455
}
5556

5657
/// The filename in the top-level `target` directory where we store

src/cargo/core/compiler/mod.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,20 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc<dyn Executor>) -> Car
333333
},
334334
)
335335
.map_err(verbose_if_simple_exit_code)
336-
.with_context(|| format!("could not compile `{}`", name))?;
336+
.with_context(|| {
337+
// adapted from rustc_errors/src/lib.rs
338+
let warnings = match output_options.warnings_seen {
339+
0 => String::new(),
340+
1 => "; 1 warning emitted".to_string(),
341+
count => format!("; {} warnings emitted", count),
342+
};
343+
let errors = match output_options.errors_seen {
344+
0 => String::new(),
345+
1 => " due to previous error".to_string(),
346+
count => format!(" due to {} previous errors", count),
347+
};
348+
format!("could not compile `{}`{}{}", name, errors, warnings)
349+
})?;
337350
}
338351

339352
if rustc_dep_info_loc.exists() {
@@ -1161,6 +1174,8 @@ struct OutputOptions {
11611174
/// Other types of messages are processed regardless
11621175
/// of the value of this flag
11631176
show_warnings: bool,
1177+
warnings_seen: usize,
1178+
errors_seen: usize,
11641179
}
11651180

11661181
impl OutputOptions {
@@ -1177,6 +1192,8 @@ impl OutputOptions {
11771192
color,
11781193
cache_cell,
11791194
show_warnings: true,
1195+
warnings_seen: 0,
1196+
errors_seen: 0,
11801197
}
11811198
}
11821199
}
@@ -1244,7 +1261,18 @@ fn on_stderr_line_inner(
12441261
}
12451262
};
12461263

1264+
let count_diagnostic = |level, options: &mut OutputOptions| {
1265+
if level == "warning" {
1266+
options.warnings_seen += 1;
1267+
} else if level == "error" {
1268+
options.errors_seen += 1;
1269+
}
1270+
};
1271+
12471272
if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(compiler_message.get()) {
1273+
for item in &report.future_incompat_report {
1274+
count_diagnostic(&*item.diagnostic.level, options);
1275+
}
12481276
state.future_incompat_report(report.future_incompat_report);
12491277
return Ok(true);
12501278
}
@@ -1265,8 +1293,14 @@ fn on_stderr_line_inner(
12651293
#[derive(serde::Deserialize)]
12661294
struct CompilerMessage {
12671295
rendered: String,
1296+
message: String,
1297+
level: String,
12681298
}
12691299
if let Ok(mut error) = serde_json::from_str::<CompilerMessage>(compiler_message.get()) {
1300+
if error.level == "error" && error.message.starts_with("aborting due to") {
1301+
// Skip this line; we'll print our own summary at the end.
1302+
return Ok(true);
1303+
}
12701304
// state.stderr will add a newline
12711305
if error.rendered.ends_with('\n') {
12721306
error.rendered.pop();
@@ -1281,6 +1315,7 @@ fn on_stderr_line_inner(
12811315
.expect("strip should never fail")
12821316
};
12831317
if options.show_warnings {
1318+
count_diagnostic(&error.level, options);
12841319
state.stderr(rendered)?;
12851320
}
12861321
return Ok(true);
@@ -1368,6 +1403,14 @@ fn on_stderr_line_inner(
13681403
return Ok(true);
13691404
}
13701405

1406+
#[derive(serde::Deserialize)]
1407+
struct CompilerMessage {
1408+
level: String,
1409+
}
1410+
if let Ok(message) = serde_json::from_str::<CompilerMessage>(compiler_message.get()) {
1411+
count_diagnostic(&message.level, options);
1412+
}
1413+
13711414
let msg = machine_message::FromCompiler {
13721415
package_id,
13731416
manifest_path,
@@ -1399,6 +1442,8 @@ fn replay_output_cache(
13991442
color,
14001443
cache_cell: None,
14011444
show_warnings,
1445+
warnings_seen: 0,
1446+
errors_seen: 0,
14021447
};
14031448
Work::new(move |state| {
14041449
if !path.exists() {

src/cargo/lib.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,7 @@ pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
8989
/// Displays an error, and all its causes, to stderr.
9090
pub fn display_error(err: &Error, shell: &mut Shell) {
9191
debug!("display_error; err={:?}", err);
92-
let has_verbose = _display_error(err, shell, true);
93-
if has_verbose {
94-
drop(writeln!(
95-
shell.err(),
96-
"\nTo learn more, run the command again with --verbose."
97-
));
98-
}
92+
_display_error(err, shell, true);
9993
if err
10094
.chain()
10195
.any(|e| e.downcast_ref::<InternalError>().is_some())

tests/testsuite/build.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -588,12 +588,7 @@ fn cargo_compile_with_invalid_code() {
588588

589589
p.cargo("build")
590590
.with_status(101)
591-
.with_stderr_contains(
592-
"\
593-
[ERROR] could not compile `foo`
594-
595-
To learn more, run the command again with --verbose.\n",
596-
)
591+
.with_stderr_contains("[ERROR] could not compile `foo` due to previous error\n")
597592
.run();
598593
assert!(p.root().join("Cargo.lock").is_file());
599594
}

tests/testsuite/build_script.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,7 @@ fn build_deps_not_for_normal() {
14581458
.with_stderr_contains("[..]can't find crate for `aaaaa`[..]")
14591459
.with_stderr_contains(
14601460
"\
1461-
[ERROR] could not compile `foo`
1461+
[ERROR] could not compile `foo` due to previous error
14621462
14631463
Caused by:
14641464
process didn't exit successfully: [..]

tests/testsuite/check.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -803,8 +803,7 @@ fn short_message_format() {
803803
.with_stderr_contains(
804804
"\
805805
src/lib.rs:1:27: error[E0308]: mismatched types
806-
error: aborting due to previous error
807-
error: could not compile `foo`
806+
error: could not compile `foo` due to previous error
808807
",
809808
)
810809
.run();

tests/testsuite/fix.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn do_not_fix_broken_builds() {
2828
p.cargo("fix --allow-no-vcs")
2929
.env("__CARGO_FIX_YOLO", "1")
3030
.with_status(101)
31-
.with_stderr_contains("[ERROR] could not compile `foo`")
31+
.with_stderr_contains("[ERROR] could not compile `foo` due to previous error")
3232
.run();
3333
assert!(p.read_file("src/lib.rs").contains("let mut x = 3;"));
3434
}
@@ -833,8 +833,6 @@ fn prepare_for_unstable() {
833833
[ERROR] cannot migrate src/lib.rs to edition {next}
834834
Edition {next} is unstable and not allowed in this release, consider trying the nightly release channel.
835835
error: could not compile `foo`
836-
837-
To learn more, run the command again with --verbose.
838836
", next=next))
839837
.run();
840838

tests/testsuite/install.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -742,9 +742,7 @@ fn compile_failure() {
742742
found at `[..]target`
743743
744744
Caused by:
745-
could not compile `foo`
746-
747-
To learn more, run the command again with --verbose.
745+
could not compile `foo` due to previous error
748746
",
749747
)
750748
.run();

0 commit comments

Comments
 (0)