Skip to content

Add debug_assert and debug_assert_eq macros #13789

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 2, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions src/libcollections/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) };
Expand All @@ -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))
}
Expand All @@ -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))
}
Expand All @@ -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))
Expand All @@ -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);
Expand All @@ -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;

Expand Down
6 changes: 3 additions & 3 deletions src/libstd/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()}
}

Expand Down Expand Up @@ -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);
}
}
Expand All @@ -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);
}
}
Expand Down
57 changes: 52 additions & 5 deletions src/libstd/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,6 @@ macro_rules! assert(
fail!("assertion failed: {:s}", stringify!($cond))
}
);
($cond:expr, $msg:expr) => (
if !$cond {
fail!($msg)
}
);
($cond:expr, $($arg:expr),+) => (
if !$cond {
fail!($($arg),+)
Expand Down Expand Up @@ -130,6 +125,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.
Expand Down
12 changes: 4 additions & 8 deletions src/libstd/sync/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Expand All @@ -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;
}
}
Expand All @@ -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 };
}
}
Expand All @@ -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
Expand Down