Change:
This code: Creates this diagnostic: I ran (note that I created a local project called playground) which created this output: This told me to create an issue here. Going into more depth regarding the issue - the macro expands after one step like so: and we can see where the issue is: These parentheses are indeed fully removable, and it points to an issue in the macro definition. By changing to the compiler no longer emits the warning, because now it expands to which is properly recognized as a tuple with one element, rather than a type surrounded by redundant parentheses. Another way to fix it is to remove the outer parentheses in the macro call: which does compile without warnings, but breaks usage of the macro with tuples with more than two elements: as while its fine to remove the parentheses when there is only one element between the angle brackets ( to ), it is not fine when there are more than one element in the tuple ( to ). Importantly, the compiler still emits the unused parentheses warning and suggests their removal when the macro is called with three types when you haven't removed the parentheses (). Therefore, part of the issue is that rustc detects the problem, and assumes it can fix it by going straight to the macro and correcting it, neglecting previous expansions of the macro which require the currently redundant parentheses. I say part of the issue, because going back to the original diagnostic: rustc marks and as removable, and it suggests you do so: when the diagnostic should really only be suggesting the removal of the outer brackets. I'm not too sure why this one happens. Using Syn's terminology, my best guess is that it has something to do with the span of the outer parentheses including the inner and after expansion. : Also tried with nightly (had identical results):

Discussion:
// Otherwise proceed with linting. _ => {} } <del> let spans = inner .span .find_ancestor_inside(value.span) .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))); </del> <ins> let spans = if !value.span.from_expansion() { inner .span .find_ancestor_inside(value.span) .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))) } else { None }; </ins> self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space, false); } }

if self.with_self_ty_parens && b.generic_params.len() > 0 => {} ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} _ => { <del> let spans = r .span .find_ancestor_inside(ty.span) .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))); </del> <ins> let spans = if !ty.span.from_expansion() { r.span .find_ancestor_inside(ty.span) .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) } else { None }; </ins> self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); } }

<ins> //@ run-pass #![warn(unused_parens)] #![allow(dead_code)] trait Foo { fn bar(); fn tar(); } macro_rules! unused_parens { ($ty:ident) => { impl<$ty: Foo> Foo for ($ty,) { fn bar() { <$ty>::bar() } fn tar() {} } }; ($ty:ident $(, $rest:ident)*) => { impl<$ty: Foo, $($rest: Foo),*> Foo for ($ty, $($rest),*) { fn bar() { <$ty>::bar(); <($($rest),*)>::bar() //~WARN unnecessary parentheses around type } fn tar() { let (_t) = 1; //~WARN unnecessary parentheses around pattern //~| WARN unnecessary parentheses around pattern let (_t1,) = (1,); let (_t2, _t3) = (1, 2); } } unused_parens!($($rest),*); } } unused_parens!(T1, T2, T3); fn main() {} </ins>

<ins> warning: unnecessary parentheses around pattern --> $DIR/unused-parens-in-macro-issue-120642.rs:26:19 | LL |               let (_t) = 1; |                   ^^^^ ... LL | unused_parens!(T1, T2, T3); | -------------------------- in this macro invocation | note: the lint level is defined here --> $DIR/unused-parens-in-macro-issue-120642.rs:3:9 | LL | #![warn(unused_parens)] |         ^^^^^^^^^^^^^ = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info) warning: unnecessary parentheses around type --> $DIR/unused-parens-in-macro-issue-120642.rs:23:18 | LL |                 <($($rest),*)>::bar() |                  ^^^^^^^^^^^^ ... LL | unused_parens!(T1, T2, T3); | -------------------------- in this macro invocation | = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info) warning: unnecessary parentheses around pattern --> $DIR/unused-parens-in-macro-issue-120642.rs:26:19 | LL |               let (_t) = 1; |                   ^^^^ ... LL | unused_parens!(T1, T2, T3); | -------------------------- in this macro invocation | = note: this warning originates in the macro `unused_parens` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 3 warnings emitted </ins>