Change:
Basically just change this macro to recognize and discard the trailing comma.
That macro declaration is formatted in a weird way. But anyway it should be enough to add to the rule (unless accepting multiple trailing commas is undesired). I could mentor.
How about this:
Out of curiosity, why doesn't rust allow trailing commas after automatically? Does it make it hard to write some macros? Alternately, why isn't there a (optional) repetition specification (e.g. would be 0 or 1 times)?
The extra rule is fine too. It's just more annoying (extra repetition). And there's no technical reason not to support one-or-none patterns as far as I'm aware.
Made a PR :)

Discussion:
/// Declare a static `LintArray` and return it as an expression. #[macro_export] <del> macro_rules! lint_array { ($( $lint:expr ),*) => ( { static ARRAY: LintArray = &[ $( &$lint ),* ]; ARRAY } ) } </del> <ins> macro_rules! lint_array { ($( $lint:expr ),*,) => { lint_array!( $( $lint ),* ) }; ($( $lint:expr ),*) => {{ static ARRAY: LintArray = &[ $( &$lint ),* ]; ARRAY }} } </ins> pub type LintArray = &'static [&'static &'static Lint];

use rustc::hir; use syntax::attr; <del> declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); </del> <ins> macro_rules! fake_lint_pass { ($struct:ident, $lints:expr, $($attr:expr),*) => { struct $struct; impl LintPass for $struct { fn get_lints(&self) -> LintArray { $lints } } </ins> <del> struct Pass; </del> <ins> impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $struct { fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { $( if !attr::contains_name(&krate.attrs, $attr) { cx.span_lint(CRATE_NOT_OKAY, krate.span, &format!("crate is not marked with #![{}]", $attr)); } )* } } </ins> <del> impl LintPass for Pass { fn get_lints(&self) -> LintArray { lint_array!(CRATE_NOT_OKAY) </del> } } <del> impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); } } </del> <ins> declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); declare_lint!(CRATE_NOT_RED, Warn, "crate not marked with #![crate_red]"); declare_lint!(CRATE_NOT_BLUE, Warn, "crate not marked with #![crate_blue]"); declare_lint!(CRATE_NOT_GREY, Warn, "crate not marked with #![crate_grey]"); declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]"); fake_lint_pass! { PassOkay, lint_array!(CRATE_NOT_OKAY), // Single lint "crate_okay" } fake_lint_pass! { PassRedBlue, lint_array!(CRATE_NOT_RED, CRATE_NOT_BLUE), // Multiple lints "crate_red", "crate_blue" } fake_lint_pass! { PassGreyGreen, lint_array!(CRATE_NOT_GREY, CRATE_NOT_GREEN, ), // Trailing comma "crate_grey", "crate_green" </ins> } #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { <del> reg.register_late_lint_pass(box Pass); </del> <ins> reg.register_late_lint_pass(box PassOkay); reg.register_late_lint_pass(box PassRedBlue); reg.register_late_lint_pass(box PassGreyGreen); </ins> }

#![feature(plugin, custom_attribute)] #![plugin(lint_for_crate)] #![crate_okay] <ins> #![crate_blue] #![crate_red] #![crate_grey] #![crate_green] </ins> pub fn main() { }