Add debug_assert and debug_assert_eq macros

I also switched some `assert!` calls over to `debug_assert!`.

Closes #12049.

RFC: 0015-assert
This commit is contained in:
Steven Fackler 2014-04-26 18:25:20 -07:00
parent 9f836d5a53
commit b0b7c252d7
4 changed files with 65 additions and 23 deletions

View File

@ -278,8 +278,7 @@ mod table {
/// the appropriate types to pass on to most of the other functions in
/// this module.
pub fn peek(&self, index: uint) -> BucketState {
// FIXME #12049
if cfg!(test) { assert!(index < self.capacity) }
debug_assert!(index < self.capacity);
let idx = index as int;
let hash = unsafe { *self.hashes.offset(idx) };
@ -306,8 +305,7 @@ mod table {
let idx = index.idx;
unsafe {
// FIXME #12049
if cfg!(test) { assert!(*self.hashes.offset(idx) != EMPTY_BUCKET) }
debug_assert!(*self.hashes.offset(idx) != EMPTY_BUCKET);
(&'a *self.keys.offset(idx),
&'a *self.vals.offset(idx))
}
@ -319,8 +317,7 @@ mod table {
let idx = index.idx;
unsafe {
// FIXME #12049
if cfg!(test) { assert!(*self.hashes.offset(idx) != EMPTY_BUCKET) }
debug_assert!(*self.hashes.offset(idx) != EMPTY_BUCKET);
(&'a *self.keys.offset(idx),
&'a mut *self.vals.offset(idx))
}
@ -332,8 +329,7 @@ mod table {
let idx = index.idx;
unsafe {
// FIXME #12049
if cfg!(test) { assert!(*self.hashes.offset(idx) != EMPTY_BUCKET) }
debug_assert!(*self.hashes.offset(idx) != EMPTY_BUCKET);
(transmute(self.hashes.offset(idx)),
&'a mut *self.keys.offset(idx),
&'a mut *self.vals.offset(idx))
@ -351,8 +347,7 @@ mod table {
let idx = index.idx;
unsafe {
// FIXME #12049
if cfg!(test) { assert_eq!(*self.hashes.offset(idx), EMPTY_BUCKET) }
debug_assert_eq!(*self.hashes.offset(idx), EMPTY_BUCKET);
*self.hashes.offset(idx) = hash.inspect();
move_val_init(&mut *self.keys.offset(idx), k);
move_val_init(&mut *self.vals.offset(idx), v);
@ -371,8 +366,7 @@ mod table {
let idx = index.idx;
unsafe {
// FIXME #12049
if cfg!(test) { assert!(*self.hashes.offset(idx) != EMPTY_BUCKET) }
debug_assert!(*self.hashes.offset(idx) != EMPTY_BUCKET);
*self.hashes.offset(idx) = EMPTY_BUCKET;

View File

@ -93,7 +93,7 @@ impl<T> RefCell<T> {
/// 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);
}
}

View File

@ -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.

View File

@ -86,8 +86,7 @@ impl<T: Send> UnsafeArc<T> {
#[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<T: Send> UnsafeArc<T> {
#[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<T: Send> Clone for UnsafeArc<T> {
// 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<T> Drop for UnsafeArc<T>{
// 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