-
-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Description
I tried this code:
use std::{assert_matches, debug_assert_matches};
#[derive(Debug)]
struct LoudDrop;
impl Drop for LoudDrop {
fn drop(&mut self) {
println!("drop");
}
}
fn make() -> LoudDrop {
LoudDrop
}
fn discard<T>(value: T, _: &LoudDrop) -> T {
value
}
fn main() {
println!("assert_eq");
(assert_eq!((), discard((), &make())), println!("after"));
println!();
println!("debug_assert_eq");
(debug_assert_eq!((), discard((), &make())), println!("after"));
println!();
println!("assert_matches");
(assert_matches!(discard((), &make()), ()), println!("after"));
println!();
println!("debug_assert_matches");
(debug_assert_matches!(discard((), &make()), ()), println!("after"));
println!();
println!("assert");
(assert!(discard(true, &make())), println!("after"));
println!();
println!("debug_assert");
(debug_assert!(discard(true, &make())), println!("after"));
}I expected the temporary scopes to be the same regardless of whether I use the debug_ variant of the macros or not. Instead, the code outputs the following:
assert_eq
after
drop
debug_assert_eq
drop
after
assert_matches
after
drop
debug_assert_matches
drop
after
assert
drop
after
debug_assert
drop
after
That is, debug_assert_eq, debug_assert_matches, assert, and debug_assert each introduces a temporary scope, causing temporaries to be dropped as soon as execution of the macro call finishes. However, assert_eq and assert_matches each does not introduce a temporary scope, causing temporaries to only be dropped at the next surrounding temporary scope, potentially after other code has executed outside the macro call. This seems inconsistent, although I'm not sure if this could affect real code in practice.
(Note: assert_matches and debug_assert_matches are stable in 1.95.0 beta.)
The reason assert_eq does not introduce a temporary scope is because, assert_eq!(expr1, expr2) expands to match (&expr1, &expr2) { .... }. And match does not introduce a temporary scope for the scrutinee. Similarly, assert_matches!(expr, pat) expands to match expr { .... }.
In contrast, assert!(expr) expands to if !expr { .... }. And if introduces a temporary scope for the condition expression.
The reference documents this difference in behavior between match and if.
The reason debug_assert_eq introduces a temporary scope is because, debug_assert_eq!(expr1, expr2) expands to if cfg!(debug_assertions) { assert_eq!(expr1, expr2); }. And the semicolon introduces a temporary scope.
cc @dianne
Meta
Reproducible on the playground with version 1.96.0-nightly (2026-03-24 362211dc29abc4e8f8cf)