Avoid .take().unwrap() with FnOnce closures
This commit is contained in:
parent
a7061d02e1
commit
4ffd9f49c3
@ -106,7 +106,7 @@
|
||||
#![allow(unknown_features)]
|
||||
#![feature(macro_rules, globs, linkage, thread_local, asm)]
|
||||
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
|
||||
#![feature(import_shadowing, slicing_syntax)]
|
||||
#![feature(import_shadowing, slicing_syntax, tuple_indexing)]
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
// Don't link to std. We are std.
|
||||
|
@ -57,22 +57,17 @@
|
||||
//!
|
||||
//! Currently Rust uses unwind runtime provided by libgcc.
|
||||
|
||||
use core::prelude::*;
|
||||
use prelude::*;
|
||||
|
||||
use any::Any;
|
||||
use boxed::Box;
|
||||
use cmp;
|
||||
use failure;
|
||||
use fmt;
|
||||
use intrinsics;
|
||||
use libc::c_void;
|
||||
use mem;
|
||||
use raw::Closure;
|
||||
use str::StrAllocating;
|
||||
use string::String;
|
||||
use sync::atomic;
|
||||
use sync::{Once, ONCE_INIT};
|
||||
use vec::Vec;
|
||||
|
||||
use sys_common::thread_info;
|
||||
use rt::libunwind as uw;
|
||||
@ -119,10 +114,9 @@ static CALLBACK_CNT: atomic::AtomicUint = atomic::INIT_ATOMIC_UINT;
|
||||
/// guaranteed that a rust task is in place when invoking this function.
|
||||
/// Unwinding twice can lead to resource leaks where some destructors are not
|
||||
/// run.
|
||||
pub unsafe fn try(f: ||) -> ::core::result::Result<(), Box<Any + Send>> {
|
||||
let closure: Closure = mem::transmute(f);
|
||||
let ep = rust_try(try_fn, closure.code as *mut c_void,
|
||||
closure.env as *mut c_void);
|
||||
pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
|
||||
let mut f = Some(f);
|
||||
let ep = rust_try(try_fn::<F>, &mut f as *mut _ as *mut c_void);
|
||||
return if ep.is_null() {
|
||||
Ok(())
|
||||
} else {
|
||||
@ -133,14 +127,9 @@ pub unsafe fn try(f: ||) -> ::core::result::Result<(), Box<Any + Send>> {
|
||||
Err(cause.unwrap())
|
||||
};
|
||||
|
||||
extern fn try_fn(code: *mut c_void, env: *mut c_void) {
|
||||
unsafe {
|
||||
let closure: || = mem::transmute(Closure {
|
||||
code: code as *mut (),
|
||||
env: env as *mut (),
|
||||
});
|
||||
closure();
|
||||
}
|
||||
extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
|
||||
let opt_closure = opt_closure as *mut Option<F>;
|
||||
unsafe { (*opt_closure).take().unwrap()(); }
|
||||
}
|
||||
|
||||
#[link(name = "rustrt_native", kind = "static")]
|
||||
@ -152,8 +141,7 @@ pub unsafe fn try(f: ||) -> ::core::result::Result<(), Box<Any + Send>> {
|
||||
// When f(...) returns normally, the return value is null.
|
||||
// When f(...) throws, the return value is a pointer to the caught
|
||||
// exception object.
|
||||
fn rust_try(f: extern "C" fn(*mut c_void, *mut c_void),
|
||||
code: *mut c_void,
|
||||
fn rust_try(f: extern fn(*mut c_void),
|
||||
data: *mut c_void) -> *mut uw::_Unwind_Exception;
|
||||
}
|
||||
}
|
||||
|
@ -60,12 +60,11 @@ pub fn set_unwinding(unwinding: bool) {
|
||||
|
||||
pub fn set(stack_bounds: (uint, uint), stack_guard: uint, thread: Thread) {
|
||||
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
|
||||
let mut thread_opt = Some(thread); // option dance
|
||||
THREAD_INFO.with(|c| *c.borrow_mut() = Some(ThreadInfo{
|
||||
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
|
||||
stack_bounds: stack_bounds,
|
||||
stack_guard: stack_guard,
|
||||
unwinding: false,
|
||||
thread: thread_opt.take().unwrap(),
|
||||
thread: thread,
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -243,17 +243,20 @@ impl Cfg {
|
||||
// the thread itself. For these reasons, this unsafety should be ok.
|
||||
unsafe {
|
||||
let mut output = None;
|
||||
let mut f_opt = Some( // option dance
|
||||
if stdout.is_some() || stderr.is_some() {
|
||||
proc() {
|
||||
let _ = stdout.map(stdio::set_stdout);
|
||||
let _ = stderr.map(stdio::set_stderr);
|
||||
f()
|
||||
}
|
||||
} else {
|
||||
f
|
||||
});
|
||||
let try_result = unwind::try(|| output = Some((f_opt.take().unwrap())()));
|
||||
let f = if stdout.is_some() || stderr.is_some() {
|
||||
proc() {
|
||||
let _ = stdout.map(stdio::set_stdout);
|
||||
let _ = stderr.map(stdio::set_stderr);
|
||||
f()
|
||||
}
|
||||
} else {
|
||||
f
|
||||
};
|
||||
|
||||
let try_result = {
|
||||
let ptr = &mut output;
|
||||
unwind::try(move || *ptr = Some(f()))
|
||||
};
|
||||
match (output, try_result) {
|
||||
(Some(data), Ok(_)) => after(Ok(data)),
|
||||
(None, Err(cause)) => after(Err(cause)),
|
||||
|
@ -217,9 +217,8 @@ impl<T: 'static> Key<T> {
|
||||
/// This function will `panic!()` if the key currently has its
|
||||
/// destructor running, and it **may** panic if the destructor has
|
||||
/// previously been run for this thread.
|
||||
pub fn with<R, F>(&'static self, f: F) -> R where
|
||||
F: FnOnce(&T) -> R,
|
||||
{
|
||||
pub fn with<F, R>(&'static self, f: F) -> R
|
||||
where F: FnOnce(&T) -> R {
|
||||
let slot = (self.inner)();
|
||||
unsafe {
|
||||
let slot = slot.get().expect("cannot access a TLS value during or \
|
||||
|
@ -262,4 +262,3 @@ mod tests {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,9 @@
|
||||
|
||||
; See also: libstd/rt/unwind.rs
|
||||
|
||||
define i8* @rust_try(void (i8*,i8*)* %f, i8* %fptr, i8* %env) {
|
||||
define i8* @rust_try(void (i8*)* %f, i8* %env) {
|
||||
|
||||
%1 = invoke i8* @rust_try_inner(void (i8*,i8*)* %f, i8* %fptr, i8* %env)
|
||||
%1 = invoke i8* @rust_try_inner(void (i8*)* %f, i8* %env)
|
||||
to label %normal
|
||||
unwind label %catch
|
||||
|
||||
@ -30,9 +30,9 @@ catch:
|
||||
ret i8* null
|
||||
}
|
||||
|
||||
define internal i8* @rust_try_inner(void (i8*,i8*)* %f, i8* %fptr, i8* %env) {
|
||||
define internal i8* @rust_try_inner(void (i8*)* %f, i8* %env) {
|
||||
|
||||
invoke void %f(i8* %fptr, i8* %env)
|
||||
invoke void %f(i8* %env)
|
||||
to label %normal
|
||||
unwind label %catch
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user