Repository: brendanzab/approx (language: rust)

Issue:
Inconsistent temporary value behavior with `assert_eq!`
For example, in this code:

```rust
fn foo(x: &[f64]) {
    assert_eq!(vec![0.0].as_slice(), x); // OK.
    approx::assert_relative_eq!(vec![0.0].as_slice(), x); // Error.
}
```

`assert_eq!` works fine, but `approx::assert_relative_eq` reports “temporary value dropped while borrowed” error.
Inconsistent temporary value behavior with `assert_eq!`
For example, in this code:

```rust
fn foo(x: &[f64]) {
    assert_eq!(vec![0.0].as_slice(), x); // OK.
    approx::assert_relative_eq!(vec![0.0].as_slice(), x); // Error.
}
```

`assert_eq!` works fine, but `approx::assert_relative_eq` reports “temporary value dropped while borrowed” error.
Inconsistent temporary value behavior with `assert_eq!`
For example, in this code:

```rust
fn foo(x: &[f64]) {
    assert_eq!(vec![0.0].as_slice(), x); // OK.
    approx::assert_relative_eq!(vec![0.0].as_slice(), x); // Error.
}
```

`assert_eq!` works fine, but `approx::assert_relative_eq` reports “temporary value dropped while borrowed” error.
clippy::if_then_panic warning (nightly)
This is not a pressing issue yet, but it appears in a nightly version of clippy, so you might be interested in addressing the lint ahead of time.

I'm using this simple snippet:
```rs
use approx::assert_relative_eq;

fn main() {
    assert_relative_eq!(1.0, 2.0);
}
```

When running `cargo +nightly clippy`, I get:
```rs
warning: only a `panic!` in `if`-then statement
 --> src\main.rs:4:2
  |
4 |     assert_relative_eq!(1.0, 2.0);
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(clippy::if_then_panic)]` on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
  = note: this warning originates in the macro `__assert_approx` (in Nightly builds, run with -Z macro-backtrace for more info)
```

This occurred in the CI of the downstream project [godot-rust](https://github.com/godot-rust/godot-rust), which treats clippy warnings as errors (the nightly workflow still passes though).

---

It has to do with how the `__assert_approx` macro is implemented.
Basically, the lint tries to detect the structure
```rs
if !cond { panic!(msg); }
```
and transform it into
```rs
assert!(cond, msg);
```

This would be one option to fix it, another would be to `#[allow(clippy::if_then_panic)]` the relevant statements.

I'm using `rustc 1.57.0-nightly (5b210643e 2021-10-11)`.


Discussion / hints:

Fix patch:
diff --git a/src/macros.rs b/src/macros.rs
index 8316677..1c6b2ce 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -82,37 +82,39 @@ macro_rules! ulps_ne {
 #[macro_export]
 macro_rules! __assert_approx {
     ($eq:ident, $given:expr, $expected:expr) => {{
-        let (given, expected) = (&($given), &($expected));
-
-        assert!($eq!(*given, *expected),
+        match (&($given), &($expected)) {
+            (given, expected) => assert!(
+                $eq!(*given, *expected),
 "assert_{}!({}, {})
 
     left  = {:?}
     right = {:?}
 
 ",
-            stringify!($eq),
-            stringify!($given),
-            stringify!($expected),
-            given, expected,
-        );
+                stringify!($eq),
+                stringify!($given),
+                stringify!($expected),
+                given, expected,
+            ),
+        }
     }};
     ($eq:ident, $given:expr, $expected:expr, $($opt:ident = $val:expr),+) => {{
-        let (given, expected) = (&($given), &($expected));
-
-        assert!($eq!(*given, *expected, $($opt = $val),+),
+        match (&($given), &($expected)) {
+            (given, expected) => assert!(
+                $eq!(*given, *expected, $($opt = $val),+),
 "assert_{}!({}, {}, {})
 
     left  = {:?}
     right = {:?}
 
 ",
-            stringify!($eq),
-            stringify!($given),
-            stringify!($expected),
-            stringify!($($opt = $val),+),
-            given, expected,
-        );
+                stringify!($eq),
+                stringify!($given),
+                stringify!($expected),
+                stringify!($($opt = $val),+),
+                given, expected,
+            ),
+        }
     }};
 }
 


Test patch:
diff --git a/tests/macros.rs b/tests/macros.rs
index 865da16..223d89c 100644
--- a/tests/macros.rs
+++ b/tests/macros.rs
@@ -96,3 +96,10 @@ fn test_ulps_ne_trailing_commas() {
     let _: bool = ulps_ne!(1.0, 1.0,);
     let _: bool = ulps_ne!(1.0, 1.0, epsilon = 1.0, max_ulps = 1,);
 }
+
+#[test]
+fn test_rvalue_arguments() {
+    assert_abs_diff_eq!(vec![0.0].as_slice(), vec![0.0].as_slice());
+    assert_relative_eq!(vec![0.0].as_slice(), vec![0.0].as_slice());
+    assert_ulps_eq!(vec![0.0].as_slice(), vec![0.0].as_slice());
+}