Skip to content

Commit 5fc9621

Browse files
authored
Rollup merge of rust-lang#58630 - nnethercote:fix-fold_clobber, r=petrochenkov
Make `visit_clobber` panic-safe. Local measurements indicate the performance effect is negligible. r? @petrochenkov
2 parents 6d30b58 + eddd07c commit 5fc9621

File tree

1 file changed

+10
-2
lines changed

1 file changed

+10
-2
lines changed

src/libsyntax/mut_visit.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use syntax_pos::Span;
2121

2222
use rustc_data_structures::sync::Lrc;
2323
use std::ops::DerefMut;
24+
use std::{panic, process, ptr};
2425

2526
pub trait ExpectOne<A: Array> {
2627
fn expect_one(self, err: &'static str) -> A::Item;
@@ -305,11 +306,18 @@ pub trait MutVisitor: Sized {
305306

306307
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
307308
/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
308-
/// method.
309+
/// method. Abort the program if the closure panics.
309310
//
310311
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
311312
pub fn visit_clobber<T, F>(t: &mut T, f: F) where F: FnOnce(T) -> T {
312-
unsafe { std::ptr::write(t, f(std::ptr::read(t))); }
313+
unsafe {
314+
// Safe because `t` is used in a read-only fashion by `read()` before
315+
// being overwritten by `write()`.
316+
let old_t = ptr::read(t);
317+
let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t)))
318+
.unwrap_or_else(|_| process::abort());
319+
ptr::write(t, new_t);
320+
}
313321
}
314322

315323
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.

0 commit comments

Comments
 (0)