From 293f662ca94d6f1eac749da55f5ff924c87fd1d5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 7 Oct 2022 13:45:41 -0700 Subject: [PATCH] Make tests capture the error printed by a Result return --- library/std/src/io/mod.rs | 1 + library/std/src/io/stdio.rs | 28 ++++++++++++++++++++++------ library/std/src/process.rs | 4 +--- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index eeace2c43c4..cceef539b90 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -262,6 +262,7 @@ #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] pub use self::buffered::WriterPanicked; +pub(crate) use self::stdio::attempt_print_to_stderr; #[unstable(feature = "internal_output_capture", issue = "none")] #[doc(no_inline, hidden)] pub use self::stdio::set_output_capture; diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 2dc12a18a8a..4ccb2bf3231 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -999,7 +999,18 @@ fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) where T: Write, { - if OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) + if print_to_buffer_if_capture_used(args) { + // Successfully wrote to capture buffer. + return; + } + + if let Err(e) = global_s().write_fmt(args) { + panic!("failed printing to {label}: {e}"); + } +} + +fn print_to_buffer_if_capture_used(args: fmt::Arguments<'_>) -> bool { + OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) && OUTPUT_CAPTURE.try_with(|s| { // Note that we completely remove a local sink to write to in case // our printing recursively panics/prints, so the recursive @@ -1009,14 +1020,19 @@ fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) s.set(Some(w)); }) }) == Ok(Some(())) - { - // Successfully wrote to capture buffer. +} + +/// Used by impl Termination for Result to print error after `main` or a test +/// has returned. Should avoid panicking, although we can't help it if one of +/// the Display impls inside args decides to. +pub(crate) fn attempt_print_to_stderr(args: fmt::Arguments<'_>) { + if print_to_buffer_if_capture_used(args) { return; } - if let Err(e) = global_s().write_fmt(args) { - panic!("failed printing to {label}: {e}"); - } + // Ignore error if the write fails, for example because stderr is already + // closed. There is not much point panicking at this point. + let _ = stderr().write_fmt(args); } #[unstable( diff --git a/library/std/src/process.rs b/library/std/src/process.rs index d91d4fa64ca..e08ea8f9a5f 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2200,9 +2200,7 @@ fn report(self) -> ExitCode { match self { Ok(val) => val.report(), Err(err) => { - // Ignore error if the write fails, for example because stderr is - // already closed. There is not much point panicking at this point. - let _ = writeln!(io::stderr(), "Error: {err:?}"); + io::attempt_print_to_stderr(format_args_nl!("Error: {err:?}")); ExitCode::FAILURE } }