Merge set_panic and set_print into set_output_capture.
There were no use cases for setting them separately. Merging them simplifies some things.
This commit is contained in:
parent
08b7cb79e0
commit
aff7bd66e8
13 changed files with 57 additions and 131 deletions
|
@ -1,6 +1,6 @@
|
||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(set_stdio)]
|
#![feature(internal_output_capture)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(generator_trait)]
|
#![feature(generator_trait)]
|
||||||
#![feature(generators)]
|
#![feature(generators)]
|
||||||
|
|
|
@ -148,7 +148,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
|
||||||
|
|
||||||
let main_handler = move || {
|
let main_handler = move || {
|
||||||
rustc_span::with_session_globals(edition, || {
|
rustc_span::with_session_globals(edition, || {
|
||||||
io::set_panic(stderr.clone());
|
io::set_output_capture(stderr.clone());
|
||||||
f()
|
f()
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
@ -186,7 +186,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
|
||||||
// on the new threads.
|
// on the new threads.
|
||||||
let main_handler = move |thread: rayon::ThreadBuilder| {
|
let main_handler = move |thread: rayon::ThreadBuilder| {
|
||||||
rustc_span::SESSION_GLOBALS.set(session_globals, || {
|
rustc_span::SESSION_GLOBALS.set(session_globals, || {
|
||||||
io::set_panic(stderr.clone());
|
io::set_output_capture(stderr.clone());
|
||||||
thread.run()
|
thread.run()
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
@ -269,20 +269,18 @@ pub use self::buffered::{BufReader, BufWriter, LineWriter};
|
||||||
pub use self::cursor::Cursor;
|
pub use self::cursor::Cursor;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::error::{Error, ErrorKind, Result};
|
pub use self::error::{Error, ErrorKind, Result};
|
||||||
|
#[unstable(feature = "internal_output_capture", issue = "none")]
|
||||||
|
#[doc(no_inline, hidden)]
|
||||||
|
pub use self::stdio::set_output_capture;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
|
pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
|
pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
|
||||||
#[unstable(feature = "print_internals", issue = "none")]
|
#[unstable(feature = "print_internals", issue = "none")]
|
||||||
pub use self::stdio::{_eprint, _print};
|
pub use self::stdio::{_eprint, _print};
|
||||||
#[unstable(feature = "libstd_io_internals", issue = "42788")]
|
|
||||||
#[doc(no_inline, hidden)]
|
|
||||||
pub use self::stdio::{set_panic, set_print};
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::util::{copy, empty, repeat, sink, Empty, Repeat, Sink};
|
pub use self::util::{copy, empty, repeat, sink, Empty, Repeat, Sink};
|
||||||
|
|
||||||
pub(crate) use self::stdio::clone_io;
|
|
||||||
|
|
||||||
mod buffered;
|
mod buffered;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod error;
|
mod error;
|
||||||
|
|
|
@ -14,37 +14,29 @@ use crate::sync::{Arc, Mutex, MutexGuard};
|
||||||
use crate::sys::stdio;
|
use crate::sys::stdio;
|
||||||
use crate::sys_common;
|
use crate::sys_common;
|
||||||
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
||||||
use crate::thread::LocalKey;
|
|
||||||
|
|
||||||
type LocalStream = Arc<Mutex<Vec<u8>>>;
|
type LocalStream = Arc<Mutex<Vec<u8>>>;
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
/// Used by the test crate to capture the output of the print! and println! macros.
|
/// Used by the test crate to capture the output of the print macros and panics.
|
||||||
static LOCAL_STDOUT: Cell<Option<LocalStream>> = {
|
static OUTPUT_CAPTURE: Cell<Option<LocalStream>> = {
|
||||||
Cell::new(None)
|
Cell::new(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
/// Flag to indicate OUTPUT_CAPTURE is used.
|
||||||
/// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
|
|
||||||
static LOCAL_STDERR: Cell<Option<LocalStream>> = {
|
|
||||||
Cell::new(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used.
|
|
||||||
///
|
///
|
||||||
/// If both are None and were never set on any thread, this flag is set to
|
/// If it is None and was never set on any thread, this flag is set to false,
|
||||||
/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all
|
/// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time
|
||||||
/// threads, saving some time and memory registering an unused thread local.
|
/// and memory registering an unused thread local.
|
||||||
///
|
///
|
||||||
/// Note about memory ordering: This contains information about whether two
|
/// Note about memory ordering: This contains information about whether a
|
||||||
/// thread local variables might be in use. Although this is a global flag, the
|
/// thread local variable might be in use. Although this is a global flag, the
|
||||||
/// memory ordering between threads does not matter: we only want this flag to
|
/// memory ordering between threads does not matter: we only want this flag to
|
||||||
/// have a consistent order between set_print/set_panic and print_to *within
|
/// have a consistent order between set_output_capture and print_to *within
|
||||||
/// the same thread*. Within the same thread, things always have a perfectly
|
/// the same thread*. Within the same thread, things always have a perfectly
|
||||||
/// consistent order. So Ordering::Relaxed is fine.
|
/// consistent order. So Ordering::Relaxed is fine.
|
||||||
static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false);
|
static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
/// A handle to a raw instance of the standard input stream of this process.
|
/// A handle to a raw instance of the standard input stream of this process.
|
||||||
///
|
///
|
||||||
|
@ -890,70 +882,24 @@ impl fmt::Debug for StderrLock<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets the thread-local stderr handle to the specified writer
|
/// Sets the thread-local output capture buffer and returns the old one.
|
||||||
///
|
|
||||||
/// This will replace the current thread's stderr handle, returning the old
|
|
||||||
/// handle. All future calls to `panic!` and friends will emit their output to
|
|
||||||
/// this specified handle.
|
|
||||||
///
|
|
||||||
/// Note that this does not need to be called for all new threads; the default
|
|
||||||
/// output handle is to the process's stderr stream.
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
feature = "set_stdio",
|
feature = "internal_output_capture",
|
||||||
reason = "this function may disappear completely or be replaced \
|
reason = "this function is meant for use in the test crate \
|
||||||
with a more general mechanism",
|
and may disappear in the future",
|
||||||
issue = "none"
|
issue = "none"
|
||||||
)]
|
)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn set_panic(sink: Option<LocalStream>) -> Option<LocalStream> {
|
pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
|
||||||
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) {
|
||||||
// LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
|
// OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
LOCAL_STREAMS.store(true, Ordering::Relaxed);
|
OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed);
|
||||||
LOCAL_STDERR.with(move |slot| slot.replace(sink))
|
OUTPUT_CAPTURE.with(move |slot| slot.replace(sink))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets the thread-local stdout handle to the specified writer
|
/// Write `args` to the capture buffer if enabled and possible, or `global_s`
|
||||||
///
|
|
||||||
/// This will replace the current thread's stdout handle, returning the old
|
|
||||||
/// handle. All future calls to `print!` and friends will emit their output to
|
|
||||||
/// this specified handle.
|
|
||||||
///
|
|
||||||
/// Note that this does not need to be called for all new threads; the default
|
|
||||||
/// output handle is to the process's stdout stream.
|
|
||||||
#[unstable(
|
|
||||||
feature = "set_stdio",
|
|
||||||
reason = "this function may disappear completely or be replaced \
|
|
||||||
with a more general mechanism",
|
|
||||||
issue = "none"
|
|
||||||
)]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn set_print(sink: Option<LocalStream>) -> Option<LocalStream> {
|
|
||||||
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
|
||||||
// LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
LOCAL_STREAMS.store(true, Ordering::Relaxed);
|
|
||||||
LOCAL_STDOUT.with(move |slot| slot.replace(sink))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn clone_io() -> (Option<LocalStream>, Option<LocalStream>) {
|
|
||||||
// Don't waste time when LOCAL_{STDOUT,STDERR} are definitely None.
|
|
||||||
if !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
|
||||||
return (None, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let clone = |cell: &Cell<Option<LocalStream>>| {
|
|
||||||
let s = cell.take();
|
|
||||||
cell.set(s.clone());
|
|
||||||
s
|
|
||||||
};
|
|
||||||
|
|
||||||
(LOCAL_STDOUT.with(clone), LOCAL_STDERR.with(clone))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write `args` to output stream `local_s` if possible, `global_s`
|
|
||||||
/// otherwise. `label` identifies the stream in a panic message.
|
/// otherwise. `label` identifies the stream in a panic message.
|
||||||
///
|
///
|
||||||
/// This function is used to print error messages, so it takes extra
|
/// This function is used to print error messages, so it takes extra
|
||||||
|
@ -963,16 +909,12 @@ pub(crate) fn clone_io() -> (Option<LocalStream>, Option<LocalStream>) {
|
||||||
/// thread, it will just fall back to the global stream.
|
/// thread, it will just fall back to the global stream.
|
||||||
///
|
///
|
||||||
/// However, if the actual I/O causes an error, this function does panic.
|
/// However, if the actual I/O causes an error, this function does panic.
|
||||||
fn print_to<T>(
|
fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
|
||||||
args: fmt::Arguments<'_>,
|
where
|
||||||
local_s: &'static LocalKey<Cell<Option<LocalStream>>>,
|
|
||||||
global_s: fn() -> T,
|
|
||||||
label: &str,
|
|
||||||
) where
|
|
||||||
T: Write,
|
T: Write,
|
||||||
{
|
{
|
||||||
if LOCAL_STREAMS.load(Ordering::Relaxed)
|
if OUTPUT_CAPTURE_USED.load(Ordering::Relaxed)
|
||||||
&& local_s.try_with(|s| {
|
&& OUTPUT_CAPTURE.try_with(|s| {
|
||||||
// Note that we completely remove a local sink to write to in case
|
// Note that we completely remove a local sink to write to in case
|
||||||
// our printing recursively panics/prints, so the recursive
|
// our printing recursively panics/prints, so the recursive
|
||||||
// panic/print goes to the global sink instead of our local sink.
|
// panic/print goes to the global sink instead of our local sink.
|
||||||
|
@ -982,7 +924,7 @@ fn print_to<T>(
|
||||||
})
|
})
|
||||||
}) == Ok(Some(()))
|
}) == Ok(Some(()))
|
||||||
{
|
{
|
||||||
// Succesfully wrote to local stream.
|
// Succesfully wrote to capture buffer.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,7 +941,7 @@ fn print_to<T>(
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
pub fn _print(args: fmt::Arguments<'_>) {
|
pub fn _print(args: fmt::Arguments<'_>) {
|
||||||
print_to(args, &LOCAL_STDOUT, stdout, "stdout");
|
print_to(args, stdout, "stdout");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
|
@ -1010,7 +952,7 @@ pub fn _print(args: fmt::Arguments<'_>) {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
pub fn _eprint(args: fmt::Arguments<'_>) {
|
pub fn _eprint(args: fmt::Arguments<'_>) {
|
||||||
print_to(args, &LOCAL_STDERR, stderr, "stderr");
|
print_to(args, stderr, "stderr");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -207,7 +207,7 @@
|
||||||
// std may use features in a platform-specific way
|
// std may use features in a platform-specific way
|
||||||
#![allow(unused_features)]
|
#![allow(unused_features)]
|
||||||
#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))]
|
#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))]
|
||||||
#![cfg_attr(test, feature(print_internals, set_stdio, update_panic_count))]
|
#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
all(target_vendor = "fortanix", target_env = "sgx"),
|
all(target_vendor = "fortanix", target_env = "sgx"),
|
||||||
feature(slice_index_methods, coerce_unsized, sgx_platform)
|
feature(slice_index_methods, coerce_unsized, sgx_platform)
|
||||||
|
|
|
@ -24,11 +24,11 @@ use crate::sys_common::{thread_info, util};
|
||||||
use crate::thread;
|
use crate::thread;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
use crate::io::set_panic;
|
use crate::io::set_output_capture;
|
||||||
// make sure to use the stderr output configured
|
// make sure to use the stderr output configured
|
||||||
// by libtest in the real copy of std
|
// by libtest in the real copy of std
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use realstd::io::set_panic;
|
use realstd::io::set_output_capture;
|
||||||
|
|
||||||
// Binary interface to the panic runtime that the standard library depends on.
|
// Binary interface to the panic runtime that the standard library depends on.
|
||||||
//
|
//
|
||||||
|
@ -218,9 +218,9 @@ fn default_hook(info: &PanicInfo<'_>) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(local) = set_panic(None) {
|
if let Some(local) = set_output_capture(None) {
|
||||||
write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()));
|
write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()));
|
||||||
set_panic(Some(local));
|
set_output_capture(Some(local));
|
||||||
} else if let Some(mut out) = panic_output() {
|
} else if let Some(mut out) = panic_output() {
|
||||||
write(&mut out);
|
write(&mut out);
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,15 +456,15 @@ impl Builder {
|
||||||
let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None));
|
let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None));
|
||||||
let their_packet = my_packet.clone();
|
let their_packet = my_packet.clone();
|
||||||
|
|
||||||
let (stdout, stderr) = crate::io::clone_io();
|
let output_capture = crate::io::set_output_capture(None);
|
||||||
|
crate::io::set_output_capture(output_capture.clone());
|
||||||
|
|
||||||
let main = move || {
|
let main = move || {
|
||||||
if let Some(name) = their_thread.cname() {
|
if let Some(name) = their_thread.cname() {
|
||||||
imp::Thread::set_name(name);
|
imp::Thread::set_name(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::io::set_print(stdout);
|
crate::io::set_output_capture(output_capture);
|
||||||
crate::io::set_panic(stderr);
|
|
||||||
|
|
||||||
// SAFETY: the stack guard passed is the one for the current thread.
|
// SAFETY: the stack guard passed is the one for the current thread.
|
||||||
// This means the current thread's stack and the new thread's stack
|
// This means the current thread's stack and the new thread's stack
|
||||||
|
|
|
@ -184,18 +184,14 @@ where
|
||||||
let mut bs = Bencher { mode: BenchMode::Auto, summary: None, bytes: 0 };
|
let mut bs = Bencher { mode: BenchMode::Auto, summary: None, bytes: 0 };
|
||||||
|
|
||||||
let data = Arc::new(Mutex::new(Vec::new()));
|
let data = Arc::new(Mutex::new(Vec::new()));
|
||||||
let oldio = if !nocapture {
|
|
||||||
Some((io::set_print(Some(data.clone())), io::set_panic(Some(data.clone()))))
|
if !nocapture {
|
||||||
} else {
|
io::set_output_capture(Some(data.clone()));
|
||||||
None
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f)));
|
let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f)));
|
||||||
|
|
||||||
if let Some((printio, panicio)) = oldio {
|
io::set_output_capture(None);
|
||||||
io::set_print(printio);
|
|
||||||
io::set_panic(panicio);
|
|
||||||
}
|
|
||||||
|
|
||||||
let test_result = match result {
|
let test_result = match result {
|
||||||
//bs.bench(f) {
|
//bs.bench(f) {
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
#![feature(available_concurrency)]
|
#![feature(available_concurrency)]
|
||||||
#![feature(set_stdio)]
|
#![feature(internal_output_capture)]
|
||||||
#![feature(panic_unwind)]
|
#![feature(panic_unwind)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(termination_trait_lib)]
|
#![feature(termination_trait_lib)]
|
||||||
|
@ -530,11 +530,9 @@ fn run_test_in_process(
|
||||||
// Buffer for capturing standard I/O
|
// Buffer for capturing standard I/O
|
||||||
let data = Arc::new(Mutex::new(Vec::new()));
|
let data = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
|
||||||
let oldio = if !nocapture {
|
if !nocapture {
|
||||||
Some((io::set_print(Some(data.clone())), io::set_panic(Some(data.clone()))))
|
io::set_output_capture(Some(data.clone()));
|
||||||
} else {
|
}
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let start = report_time.then(Instant::now);
|
let start = report_time.then(Instant::now);
|
||||||
let result = catch_unwind(AssertUnwindSafe(testfn));
|
let result = catch_unwind(AssertUnwindSafe(testfn));
|
||||||
|
@ -543,10 +541,7 @@ fn run_test_in_process(
|
||||||
TestExecTime(duration)
|
TestExecTime(duration)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some((printio, panicio)) = oldio {
|
io::set_output_capture(None);
|
||||||
io::set_print(printio);
|
|
||||||
io::set_panic(panicio);
|
|
||||||
}
|
|
||||||
|
|
||||||
let test_result = match result {
|
let test_result = match result {
|
||||||
Ok(()) => calc_result(&desc, Ok(()), &time_opts, &exec_time),
|
Ok(()) => calc_result(&desc, Ok(()), &time_opts, &exec_time),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# `libstd_io_internals`
|
# `internal_output_capture`
|
||||||
|
|
||||||
This feature is internal to the Rust compiler and is not intended for general use.
|
This feature is internal to the Rust compiler and is not intended for general use.
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
# `set_stdio`
|
|
||||||
|
|
||||||
This feature is internal to the Rust compiler and is not intended for general use.
|
|
||||||
|
|
||||||
------------------------
|
|
|
@ -1,11 +1,11 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
// ignore-emscripten no subprocess support
|
// ignore-emscripten no subprocess support
|
||||||
|
|
||||||
#![feature(set_stdio)]
|
#![feature(internal_output_capture)]
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::io::set_panic;
|
use std::io::set_output_capture;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
pub struct A;
|
pub struct A;
|
||||||
|
@ -17,7 +17,7 @@ impl Display for A {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
set_panic(Some(Arc::new(Mutex::new(Vec::new()))));
|
set_output_capture(Some(Arc::new(Mutex::new(Vec::new()))));
|
||||||
assert!(std::panic::catch_unwind(|| {
|
assert!(std::panic::catch_unwind(|| {
|
||||||
eprintln!("{}", A);
|
eprintln!("{}", A);
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
// ignore-emscripten no threads support
|
// ignore-emscripten no threads support
|
||||||
|
|
||||||
#![feature(set_stdio)]
|
#![feature(internal_output_capture)]
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
@ -13,7 +13,7 @@ fn main() {
|
||||||
let res = thread::Builder::new().spawn({
|
let res = thread::Builder::new().spawn({
|
||||||
let data = data.clone();
|
let data = data.clone();
|
||||||
move || {
|
move || {
|
||||||
io::set_panic(Some(data));
|
io::set_output_capture(Some(data));
|
||||||
panic!("Hello, world!")
|
panic!("Hello, world!")
|
||||||
}
|
}
|
||||||
}).unwrap().join();
|
}).unwrap().join();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue