summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Nethercote <nnethercote@mozilla.com>2019-02-22 13:36:04 +1100
committerNicholas Nethercote <nnethercote@mozilla.com>2019-02-26 11:20:53 +1100
commiteddd07cc8a92dd603e9884789fb58b2d3edd2e16 (patch)
tree6bd8f9b52302208a40b8b8317ff6c5e0cede451f
parentf47ec2ad5b6887b3d400aee49e2294bd27733d18 (diff)
downloadrust-eddd07cc8a92dd603e9884789fb58b2d3edd2e16.tar.gz
Make `visit_clobber` panic-safe.
-rw-r--r--src/libsyntax/mut_visit.rs12
1 files changed, 10 insertions, 2 deletions
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 1e5eb0992bd..b7d22b3d554 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -21,6 +21,7 @@ use syntax_pos::Span;
use rustc_data_structures::sync::Lrc;
use std::ops::DerefMut;
+use std::{panic, process, ptr};
pub trait ExpectOne<A: Array> {
fn expect_one(self, err: &'static str) -> A::Item;
@@ -305,11 +306,18 @@ pub trait MutVisitor: Sized {
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
-/// method.
+/// method. Abort the program if the closure panics.
//
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_clobber<T, F>(t: &mut T, f: F) where F: FnOnce(T) -> T {
- unsafe { std::ptr::write(t, f(std::ptr::read(t))); }
+ unsafe {
+ // Safe because `t` is used in a read-only fashion by `read()` before
+ // being overwritten by `write()`.
+ let old_t = ptr::read(t);
+ let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t)))
+ .unwrap_or_else(|_| process::abort());
+ ptr::write(t, new_t);
+ }
}
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.