So I went down the list of macros in
std and tested every. single. one of them for trailing comma support in all possible locations.
By some blessing of fortune, every single “variadic” macro correctly supports trailing commas beyond a sufficient number of arguments. The majority of them forward the token list to
format_args!, which handles the commas correctly. It is only a small number of fixed argument counts that fail for each macro.
I am also delighted to report that the single most glaring “trailing comma” bug (
assert_eq!) has already been fixed in 1.22. (I only discovered this because I switched toolchains to test the unstable macros!)
Here’s the full list of failing test cases
assert!(true, ); //~ ERROR: unexpected end of macro invocation assert!(true, "hello",); //~ ERROR: unexpected end of macro invocation assert_eq!(1, 1,); // (fixed in 1.22) assert_ne!(1, 2,); // (fixed in 1.22) compile_error!("lel",); //~ ERROR: compile_error! takes 1 argument debug_assert!(true, ); //~ ERROR: unexpected end of macro invocation debug_assert!(true, "hello",); //~ ERROR: unexpected end of macro invocation debug_assert_eq!(1, 1,); // (fixed in 1.22) debug_assert_ne!(1, 2,); // (fixed in 1.22) include!("dumdum.rs",); //~ ERROR: include! takes 1 argument include_bytes!("dumdum.rs",); //~ ERROR: include_bytes! takes 1 argument include_str!("dumdum.rs",); //~ ERROR: include_str! takes 1 argument option_env!("PATH",); //~ ERROR: option_env! takes 1 argument panic!("hello",); //~ ERROR: unexpected end of macro invocation try!(Ok(()),); //~ ERROR: no rules expected the token `,` unreachable!("hello",); //~ ERROR: unexpected end of macro invocation writeln!(&mut stdout,); //~ ERROR: unexpected end of macro invocation // This one is dubious since it's not "expression-like". // That said, concat_idents! supports trailing commas... cfg!(unix,); //~ ERROR: expected 1 cfg-pattern // Not shown: // * A great number of failing cases for the unstable `select!` // * Cases that probably shouldn't succeed for `thread_local!`, but do anyways.
Some macros support trailing commas even though their documented
macro_rules!patterns suggest that they wouldn’t. This is because they’re actually compiler builtins, and the macros in std are just stubs for documentation purposes. (I think)
option_env!amusingly differ in their trailing comma support
The fact that
unimplemented!()takes format args is not only undocumented, but it also makes me sad; I’ve always wanted
unimplemented!()to take a bunch of expressions and treat them as used.
thread_local!bizarrely supports omitting the last semicolon, similar to
macro_rules!. (aside: this is above and beyond my least favorite feature of