Skip to content

Commit

Permalink
Use Vec<u8> for LOCAL_STD{OUT,ERR} instead of dyn Write.
Browse files Browse the repository at this point in the history
It was only ever used with Vec<u8> anyway. This simplifies some things.

- It no longer needs to be flushed, because that's a no-op anyway for
  a Vec<u8>.

- Writing to a Vec<u8> never fails.

- No #[cfg(test)] code is needed anymore to use `realstd` instead of
  `std`, because Vec comes from alloc, not std (like Write).
  • Loading branch information
m-ou-se committed Nov 10, 2020
1 parent ccbce1d commit f534b75
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 79 deletions.
8 changes: 2 additions & 6 deletions compiler/rustc_interface/src/util.rs
Expand Up @@ -148,9 +148,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se

let main_handler = move || {
rustc_span::with_session_globals(edition, || {
if let Some(stderr) = stderr {
io::set_panic(Some(stderr.clone()));
}
io::set_panic(stderr.clone());
f()
})
};
Expand Down Expand Up @@ -188,9 +186,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
// on the new threads.
let main_handler = move |thread: rayon::ThreadBuilder| {
rustc_span::SESSION_GLOBALS.set(session_globals, || {
if let Some(stderr) = stderr {
io::set_panic(Some(stderr.clone()));
}
io::set_panic(stderr.clone());
thread.run()
})
};
Expand Down
61 changes: 23 additions & 38 deletions library/std/src/io/stdio.rs
Expand Up @@ -16,7 +16,7 @@ use crate::sys_common;
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use crate::thread::LocalKey;

type LocalStream = Arc<Mutex<dyn Write + Send>>;
type LocalStream = Arc<Mutex<Vec<u8>>>;

thread_local! {
/// Used by the test crate to capture the output of the print! and println! macros.
Expand Down Expand Up @@ -911,13 +911,8 @@ pub fn set_panic(sink: Option<LocalStream>) -> Option<LocalStream> {
// LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
return None;
}
let s =
LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|s| {
let _ = s.lock().unwrap_or_else(|e| e.into_inner()).flush();
Some(s)
});
LOCAL_STREAMS.store(true, Ordering::Relaxed);
s
LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink))
}

/// Resets the thread-local stdout handle to the specified writer
Expand All @@ -941,13 +936,8 @@ pub fn set_print(sink: Option<LocalStream>) -> Option<LocalStream> {
// LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
return None;
}
let s =
LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|s| {
let _ = s.lock().unwrap_or_else(|e| e.into_inner()).flush();
Some(s)
});
LOCAL_STREAMS.store(true, Ordering::Relaxed);
s
LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink))
}

pub(crate) fn clone_io() -> (Option<LocalStream>, Option<LocalStream>) {
Expand All @@ -956,9 +946,10 @@ pub(crate) fn clone_io() -> (Option<LocalStream>, Option<LocalStream>) {
return (None, None);
}

LOCAL_STDOUT.with(|stdout| {
LOCAL_STDERR.with(|stderr| (stdout.borrow().clone(), stderr.borrow().clone()))
})
(
LOCAL_STDOUT.with(|s| s.borrow().clone()),
LOCAL_STDERR.with(|s| s.borrow().clone()),
)
}

/// Write `args` to output stream `local_s` if possible, `global_s`
Expand All @@ -979,28 +970,22 @@ fn print_to<T>(
) where
T: Write,
{
let result = LOCAL_STREAMS
.load(Ordering::Relaxed)
.then(|| {
local_s
.try_with(|s| {
// Note that we completely remove a local sink to write to in case
// our printing recursively panics/prints, so the recursive
// panic/print goes to the global sink instead of our local sink.
let prev = s.borrow_mut().take();
if let Some(w) = prev {
let result = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args);
*s.borrow_mut() = Some(w);
return result;
}
global_s().write_fmt(args)
})
.ok()
})
.flatten()
.unwrap_or_else(|| global_s().write_fmt(args));

if let Err(e) = result {
if LOCAL_STREAMS.load(Ordering::Relaxed)
&& local_s.try_with(|s| {
// Note that we completely remove a local sink to write to in case
// our printing recursively panics/prints, so the recursive
// panic/print goes to the global sink instead of our local sink.
s.take().map(|w| {
let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args);
*s.borrow_mut() = Some(w);
})
}) == Ok(Some(()))
{
// Succesfully wrote to local stream.
return;
}

if let Err(e) = global_s().write_fmt(args) {
panic!("failed printing to {}: {}", label, e);
}
}
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Expand Up @@ -297,6 +297,7 @@
#![feature(raw)]
#![feature(raw_ref_macros)]
#![feature(ready_macro)]
#![feature(refcell_take)]
#![feature(rustc_attrs)]
#![feature(rustc_private)]
#![feature(shrink_to)]
Expand Down
23 changes: 1 addition & 22 deletions library/std/src/panicking.rs
Expand Up @@ -219,28 +219,7 @@ fn default_hook(info: &PanicInfo<'_>) {
};

if let Some(local) = set_panic(None) {
let mut stream = local.lock().unwrap_or_else(|e| e.into_inner());

#[cfg(test)]
{
use crate::io;
struct Wrapper<'a>(&'a mut (dyn ::realstd::io::Write + Send));
impl io::Write for Wrapper<'_> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf).map_err(|_| io::ErrorKind::Other.into())
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush().map_err(|_| io::ErrorKind::Other.into())
}
}
write(&mut Wrapper(&mut *stream));
}

#[cfg(not(test))]
write(&mut *stream);

drop(stream);

write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()));
set_panic(Some(local));
} else if let Some(mut out) = panic_output() {
write(&mut out);
Expand Down
15 changes: 2 additions & 13 deletions src/test/ui/panic-while-printing.rs
Expand Up @@ -5,7 +5,7 @@

use std::fmt;
use std::fmt::{Display, Formatter};
use std::io::{self, set_panic, Write};
use std::io::set_panic;
use std::sync::{Arc, Mutex};

pub struct A;
Expand All @@ -16,19 +16,8 @@ impl Display for A {
}
}

struct Sink;

impl Write for Sink {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

fn main() {
set_panic(Some(Arc::new(Mutex::new(Sink))));
set_panic(Some(Arc::new(Mutex::new(Vec::new()))));
assert!(std::panic::catch_unwind(|| {
eprintln!("{}", A);
})
Expand Down

0 comments on commit f534b75

Please sign in to comment.