Implement RFC-2011 (Nicer assert!
messages) by c410-f3r · Pull Request #96496 · rust-lang/rust (original) (raw)
Functionality
The intention here is to show the contents of variables that are outside the declaration of assert!( ... )
.
Current behavior
fn main() { let a = 1; let b = true; assert!(a == 1 && !b); }
// Output: // // assertion failed: a == 1 && !b
New behavior with this PR
#![feature(generic_assert)]
fn main() { let a = 1; let b = true; assert!(a == 1 && !b); }
// Output: // // Assertion failed: a == 1 && !b // With captures: // a = 1 // b = true
Internals
All external assert!
variables are replaced by a block that tries to copy the intended value and then use this possibly copied element to print useful messages if a branch occurs.
fn main() { #[derive(PartialEq)] struct NoDebug(i32);
let no_debug = NoDebug(1);
let number = 3i32;
assert!(no_debug != NoDebug(2) && 1 == number);
}
With this reasoning in mind, the above assert!
will more or less expand to the following code:
#[derive(PartialEq)] struct NoDebug(i32);
let no_debug = NoDebug(1); let number = 3i32;
{ let mut __capture0 = Capture::new(); let mut __capture1 = Capture::new();
let __local_bind0 = &no_debug;
let __local_bind1 = &number;
if !(
// no_debug != NoDebug(2)
*{
(&Wrapper(__local_bind0)).try_capture(&mut __capture1);
__local_bind0
} != NoDebug(2)
// 1 == number
&& 1 == *{
(&Wrapper(__local_bind1)).try_capture(&mut __capture2);
__local_bind1
}
) {
panic!(
"Assertion failed: no_debug != NoDebug(2) && 1 == number\nWith captures:\n no_debug = {:?}\n number = {:?}",
__capture0,
__capture1,
);
}
}
The compiler "side" outputs the necessary machinery to make the library "side" decide how an element T
will or will not be printed.
Performance
It is inevitable that more instructions will be issued but probably nothing that will have a huge negative impact. Nevertheless, it is possible to optimize certain scenarios to reduce codegen.
; https://godbolt.org/z/94rE4dE4a (worst-case) example::with_generic_assert: sub rsp, 104 mov dword ptr [rsp + 16], 0 mov dword ptr [rsp + 8], 0 cmp edi, 2 je .LBB2_3 mov dword ptr [rsp + 8], 1 mov dword ptr [rsp + 12], esi cmp esi, 1 jne .LBB2_3 add rsp, 104 ret
; https://godbolt.org/z/P8T4rboac (best-case) example::with_generic_assert: sub rsp, 104 mov dword ptr [rsp + 16], 0 cmp edi, 2 je .LBB2_3 cmp esi, 1 jne .LBB2_3 add rsp, 104 ret
example::without_generic_assert: cmp edi, 2 je .LBB3_3 cmp esi, 1 jne .LBB3_3 ret