Warning: unnecessary parentheses around `if` condition

When I run below code, it shows warning: unnecessary parentheses around if condition:

#[macro_export]
macro_rules! set_bit {
    (&mut $num: expr, $n: tt, $val: tt) => {{
        println!("here");
        if $val {
            $num |= 1 << $n;
        } else {
            $num &= !(1 << $n);
        }
    }};

    (&mut $num: expr, $n: tt, ($val: tt)) => {{
        if $val {
            $num |= 1 << $n;
        } else {
            $num &= !(1 << $n);
        }
    }};
}

#[test]
fn test_set_bit() {
    let mut bit = 2;
    let disable = true;
    set_bit!(&mut bit, 1, (!disable));
    println!("{}", bit);
}

But if I remove the parentheses around the disable, it shows no rules expected the token disable, so how to fix this?

Interesting that it triggers the lint. I think the short answer is that you can just change the tt arguments to expr in this case. ! and disable count as separate token trees.

2 Likes
  • tt: a TokenTree (a single token or tokens in matching delimiters (), [], or {})

src: Macros By Example - The Rust Reference

1 Like

Got it!

Thanks!

tt is a curious thing -- often you want $($val:tt)+ to avoid problems like this, since in my experience it's somewhat rare that you want to accept just a single tt. (At least in the user-facing parts of macros. When doing tricks it can be useful to get just a single one.)

Using expr again is definitely the way to go here. But also you should feel free to suppress syntactic lints in your macros, if you want to use parens for this.

4 Likes

Also, if all else fails and the warning is about syntax just use #[allow(lint_name)] in macros. There's a bunch of times where trying to avoid syntax warnings will lead you into writing very verbose and complicated macros that do the exact same thing as their simpler counterparts. It's generated code and it will look ugly no matter how hard you try so don't feel bad adding allow attributes.

Here's an example in the wild - writing the same thing without allow would a) require a proc_macro, b) require specially handling the case for 0 arguments. So it's just simpler to ignore those warnings as they're there to warn you about potential issues.

1 Like