From b0b7c252d79f57e47af5f677b9e551f42657c509 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 26 Apr 2014 18:25:20 -0700 Subject: Add debug_assert and debug_assert_eq macros I also switched some `assert!` calls over to `debug_assert!`. Closes #12049. RFC: 0015-assert --- src/libstd/cell.rs | 6 +++--- src/libstd/macros.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/sync/arc.rs | 12 ++++-------- 3 files changed, 59 insertions(+), 11 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index ec064f4f5ec..1e4faf1a899 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -93,7 +93,7 @@ impl RefCell { /// Consumes the `RefCell`, returning the wrapped value. pub fn unwrap(self) -> T { - assert!(self.borrow.get() == UNUSED); + debug_assert!(self.borrow.get() == UNUSED); unsafe{self.value.unwrap()} } @@ -181,7 +181,7 @@ pub struct Ref<'b, T> { impl<'b, T> Drop for Ref<'b, T> { fn drop(&mut self) { let borrow = self.parent.borrow.get(); - assert!(borrow != WRITING && borrow != UNUSED); + debug_assert!(borrow != WRITING && borrow != UNUSED); self.parent.borrow.set(borrow - 1); } } @@ -202,7 +202,7 @@ pub struct RefMut<'b, T> { impl<'b, T> Drop for RefMut<'b, T> { fn drop(&mut self) { let borrow = self.parent.borrow.get(); - assert!(borrow == WRITING); + debug_assert!(borrow == WRITING); self.parent.borrow.set(UNUSED); } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index dbaef335804..58bf10d8c6a 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -130,6 +130,58 @@ macro_rules! assert_eq( }) ) +/// Ensure that a boolean expression is `true` at runtime. +/// +/// This will invoke the `fail!` macro if the provided expression cannot be +/// evaluated to `true` at runtime. +/// +/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing +/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for +/// checks that are too expensive to be present in a release build but may be +/// helpful during development. +/// +/// # Example +/// +/// ``` +/// // the failure message for these assertions is the stringified value of the +/// // expression given. +/// debug_assert!(true); +/// # fn some_expensive_computation() -> bool { true } +/// debug_assert!(some_expensive_computation()); +/// +/// // assert with a custom message +/// # let x = true; +/// debug_assert!(x, "x wasn't true!"); +/// # let a = 3; let b = 27; +/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b); +/// ``` +#[macro_export] +macro_rules! debug_assert( + ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); }) +) + +/// Asserts that two expressions are equal to each other, testing equality in +/// both directions. +/// +/// On failure, this macro will print the values of the expressions. +/// +/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by +/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!` +/// useful for checks that are too expensive to be present in a release build +/// but may be helpful during development. +/// +/// # Example +/// +/// ``` +/// let a = 3; +/// let b = 1 + 2; +/// debug_assert_eq!(a, b); +/// ``` +#[macro_export] +macro_rules! debug_assert_eq( + ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); }) +) + /// A utility macro for indicating unreachable code. It will fail if /// executed. This is occasionally useful to put after loops that never /// terminate normally, but instead directly return from a function. diff --git a/src/libstd/sync/arc.rs b/src/libstd/sync/arc.rs index 7ac7700d8d3..8d6d1c222cf 100644 --- a/src/libstd/sync/arc.rs +++ b/src/libstd/sync/arc.rs @@ -86,8 +86,7 @@ impl UnsafeArc { #[inline] pub fn get(&self) -> *mut T { unsafe { - // FIXME(#12049): this needs some sort of debug assertion - if cfg!(test) { assert!((*self.data).count.load(Relaxed) > 0); } + debug_assert!((*self.data).count.load(Relaxed) > 0); return (*self.data).data.get(); } } @@ -97,8 +96,7 @@ impl UnsafeArc { #[inline] pub fn get_immut(&self) -> *T { unsafe { - // FIXME(#12049): this needs some sort of debug assertion - if cfg!(test) { assert!((*self.data).count.load(Relaxed) > 0); } + debug_assert!((*self.data).count.load(Relaxed) > 0); return (*self.data).data.get() as *T; } } @@ -125,8 +123,7 @@ impl Clone for UnsafeArc { // synchronization. // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) let old_count = (*self.data).count.fetch_add(1, Relaxed); - // FIXME(#12049): this needs some sort of debug assertion - if cfg!(test) { assert!(old_count >= 1); } + debug_assert!(old_count >= 1); return UnsafeArc { data: self.data }; } } @@ -144,8 +141,7 @@ impl Drop for UnsafeArc{ // Because `fetch_sub` is already atomic, we do not need to synchronize with other // threads unless we are going to delete the object. let old_count = (*self.data).count.fetch_sub(1, Release); - // FIXME(#12049): this needs some sort of debug assertion - if cfg!(test) { assert!(old_count >= 1); } + debug_assert!(old_count >= 1); if old_count == 1 { // This fence is needed to prevent reordering of use of the data and deletion of // the data. Because it is marked `Release`, the decreasing of the reference count -- cgit 1.4.1-3-g733a5