@@ -389,48 +389,41 @@ pub use realstd::rt::update_panic_count;
389
389
390
390
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
391
391
pub unsafe fn try < R , F : FnOnce ( ) -> R > ( f : F ) -> Result < R , Box < Any + Send > > {
392
- struct Data < F , R > {
392
+ #[ allow( unions_with_drop_fields) ]
393
+ union Data < F , R > {
393
394
f : F ,
394
395
r : R ,
395
396
}
396
397
397
398
// We do some sketchy operations with ownership here for the sake of
398
- // performance. The `Data` structure is never actually fully valid, but
399
- // instead it always contains at least one uninitialized field. We can only
400
- // pass pointers down to `__rust_maybe_catch_panic` (can't pass objects by
401
- // value), so we do all the ownership tracking here manully.
399
+ // performance. We can only pass pointers down to
400
+ // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all
401
+ // the ownership tracking here manually using a union.
402
402
//
403
- // Note that this is all invalid if any of these functions unwind, but the
404
- // whole point of this function is to prevent that! As a result we go
405
- // through a transition where:
403
+ // We go through a transition where:
406
404
//
407
- // * First, only the closure we're going to call is initialized. The return
408
- // value is uninitialized.
405
+ // * First, we set the data to be the closure that we're going to call.
409
406
// * When we make the function call, the `do_call` function below, we take
410
- // ownership of the function pointer, replacing it with uninitialized
411
- // data. At this point the `Data` structure is entirely uninitialized, but
412
- // it won't drop due to an unwind because it's owned on the other side of
413
- // the catch panic.
407
+ // ownership of the function pointer. At this point the `Data` union is
408
+ // entirely uninitialized.
414
409
// * If the closure successfully returns, we write the return value into the
415
410
// data's return slot. Note that `ptr::write` is used as it's overwriting
416
411
// uninitialized data.
417
412
// * Finally, when we come back out of the `__rust_maybe_catch_panic` we're
418
413
// in one of two states:
419
414
//
420
415
// 1. The closure didn't panic, in which case the return value was
421
- // filled in. We have to be careful to `forget` the closure,
422
- // however, as ownership was passed to the `do_call` function.
416
+ // filled in. We move it out of `data` and return it.
423
417
// 2. The closure panicked, in which case the return value wasn't
424
- // filled in. In this case the entire `data` structure is invalid,
425
- // so we forget the entire thing .
418
+ // filled in. In this case the entire `data` union is invalid, so
419
+ // there is no need to drop anything .
426
420
//
427
421
// Once we stack all that together we should have the "most efficient'
428
422
// method of calling a catch panic whilst juggling ownership.
429
423
let mut any_data = 0 ;
430
424
let mut any_vtable = 0 ;
431
425
let mut data = Data {
432
426
f : f,
433
- r : mem:: uninitialized ( ) ,
434
427
} ;
435
428
436
429
let r = __rust_maybe_catch_panic ( do_call :: < F , R > ,
@@ -439,12 +432,9 @@ pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
439
432
& mut any_vtable) ;
440
433
441
434
return if r == 0 {
442
- let Data { f, r } = data;
443
- mem:: forget ( f) ;
444
435
debug_assert ! ( update_panic_count( 0 ) == 0 ) ;
445
- Ok ( r)
436
+ Ok ( data . r )
446
437
} else {
447
- mem:: forget ( data) ;
448
438
update_panic_count ( -1 ) ;
449
439
debug_assert ! ( update_panic_count( 0 ) == 0 ) ;
450
440
Err ( mem:: transmute ( raw:: TraitObject {
0 commit comments