Change:
The new lint for excess semicolons () has some weird behaviour when the lint is triggered inside an async function that is transformed using a procedural macro. Rustc version: 1.39.0-nightly ( 2019-08-26) Compiling this: gives this output: note how the spans are all targeting the procedural macro instead of the correct line. If I remove the procedural macro or if I remove the excess semicolon, the spans are fine. This leads me to believe that it's an error in the lint, not in the macro, but maybe I'm wrong.
It is the macro's responsibility to preserve spans. What we can do is silence warnings coming from macro's, but we do that on a lint by lint basis at the moment.
Without the excess semicolon the spans for the other warnings are correct even with the macro, which led me to believe that the macro itself is not the problem. Does that mean that the macro somehow needs to support this new lint (or some family of lints)?
The fact that the other lints trigger only if the extra semicolon is there is quite weird indeed.
At my setup they trigger always (unless the compiler does not nothing and prints nothing out), however the combination + macro + excess semicolon messes up the spans. I looked at the macro and tried to use , that didn't help.

Discussion:
} } ast::StmtKind::Semi(ref expr) => { <del> self.space_if_not_bol(); self.print_expr_outer_attr_style(expr, false); self.s.word(";"); </del> <ins> match expr.kind { // Filter out empty `Tup` exprs created for the `redundant_semicolon` // lint, as they shouldn't be visible and interact poorly // with proc macros. ast::ExprKind::Tup(ref exprs) if exprs.is_empty() && expr.attrs.is_empty() => (), _ => { self.space_if_not_bol(); self.print_expr_outer_attr_style(expr, false); self.s.word(";"); } } </ins> } ast::StmtKind::Mac(ref mac) => { let (ref mac, style, ref attrs) = **mac;

<ins> // force-host // no-prefer-dynamic #![crate_type="proc-macro"] #![crate_name="redundant_semi_proc_macro"] extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_attribute] pub fn should_preserve_spans(_attr: TokenStream, item: TokenStream) -> TokenStream { eprintln!("{:?}", item); item } </ins>

<ins> // aux-build:redundant-semi-proc-macro-def.rs #![deny(redundant_semicolon)] extern crate redundant_semi_proc_macro; use redundant_semi_proc_macro::should_preserve_spans; #[should_preserve_spans] fn span_preservation()  { let tst = 123;; //~ ERROR unnecessary trailing semicolon match tst { // Redundant semicolons are parsed as empty tuple exprs // for the lint, so ensure the lint doesn't affect // empty tuple exprs explicitly in source. 123 => (), _ => () };;; //~ ERROR unnecessary trailing semicolons } fn main() {} </ins>

<ins> TokenStream [Ident { ident: "fn", span: #0 bytes(197..199) }, Ident { ident: "span_preservation", span: #0 bytes(200..217) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(217..219) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(227..230) }, Ident { ident: "tst", span: #0 bytes(231..234) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(235..236) }, Literal { lit: Lit { kind: Integer, symbol: 123, suffix: None }, span: Span { lo: BytePos(237), hi: BytePos(240), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(240..241) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(241..242) }, Ident { ident: "match", span: #0 bytes(288..293) }, Ident { ident: "tst", span: #0 bytes(294..297) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: 123, suffix: None }, span: Span { lo: BytePos(482), hi: BytePos(485), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(486..488) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(486..488) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(489..491) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(491..492) }, Ident { ident: "_", span: #0 bytes(501..502) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(503..505) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(503..505) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(506..508) }], span: #0 bytes(298..514) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(514..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(516..517) }], span: #0 bytes(221..561) }] error: unnecessary trailing semicolon --> $DIR/redundant-semi-proc-macro.rs:9:19 | LL |     let tst = 123;; |                   ^ help: remove this semicolon | note: lint level defined here --> $DIR/redundant-semi-proc-macro.rs:3:9 | LL | #![deny(redundant_semicolon)] |         ^^^^^^^^^^^^^^^^^^^ error: unnecessary trailing semicolons --> $DIR/redundant-semi-proc-macro.rs:16:7 | LL |     };;; |       ^^ help: remove these semicolons error: aborting due to 2 previous errors </ins>