'Lint violation not caught when using macro_rules imported from another crate
I'm implementing a crate that has the purpose of wrapping some user code and make sure it is called in a certain context. I can summarize my workspace this way:
A "user_code" crate: This contains a single "user" function, which I would have no control over. Notice that it returns a u32.
pub fn addition(a: u32, b: u32) -> u32 {
a + b
}
A "wrapper" crate: This contains a macro_rules. This macro creates some modules and a caller function, which will call the user code seen above. This is a highly simplified version. Notice that the return value of addition is ignored.
#[macro_export]
macro_rules! macro_wrapper {
() => {
pub mod my_user_code {
use wrapper::*;
use user_code::*;
pub mod addition {
use wrapper::*;
use super::*;
pub fn caller(a: u32, b: u32) {
addition(a, b);
}
}
}
};
}
An "example" crate: Here I simply call the wrapper macro, in order to form the modules and functions I need and then use in the main function.
#![deny(unused_results)]
use wrapper::macro_wrapper;
macro_wrapper! {
}
fn main() {
my_user_code::addition::caller(2,3);
println!("Hello, world!");
}
This might seem like super strange code (it is) but it's a very simplified example of a legit project :)
My goal now is to make sure that this code doesn't compile because the return value of addition is not used - it was forgotten. The lint #![deny(unused_results)] seems to achieve exactly what I want.
However, this works only if, instead of use wrapper::macro_wrapper; I have the macro directly defined in the main.rs. In that case I get:
error: unused result of type `u32`
--> example\src\main.rs:14:21
|
14 | addition(a, b);
| ^^^^^^^^^^^^^^^
...
21 | / macro_wrapper! {
22 | |
23 | | }
| |_- in this macro invocation
|
note: the lint level is defined here
--> example\src\main.rs:1:9
|
1 | #![deny(unused_results)]
| ^^^^^^^^^^^^^^
= note: this error originates in the macro `macro_wrapper` (in Nightly builds, run with -Z macro-backtrace for more info)
If the macro is defined in its crate "wrapper", the code compiles and runs just fine without any error. This is not the result I expect.
What am I missing here? Thank you in advance for reading!
Solution 1:[1]
The unused_results lint doesn't get fired for macro expansions for external macros. This is by design, because this lint can be very noisy, and you can't control the expansion of external macros.
If you need that, your best bet is to mark your function as #[must_use], then #![deny(unused_must_use)]. Because the unused_must_use lint does get fired for external macros, it will work.
If you can't control the function definition, a neat trick you can use is to define a dummy function whom only job is to trigger the lint:
#[doc(hidden)]
#[must_use]
pub fn must_use<T>(v: T) -> T { v }
// In the macro...
pub fn caller(a: u32, b: u32) {
$crate::must_use(addition(a, b));
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Chayim Friedman |
