From 5fa97c35da2f0eeda4321da7fb5933490b798d79 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Tue, 6 Feb 2018 23:03:14 -0500 Subject: [PATCH 1/5] add tests for macro trailing commas --- src/test/compile-fail/macro-comma-behavior.rs | 101 +++++ src/test/compile-fail/macro-comma-support.rs | 20 + .../run-pass/auxiliary/macro-comma-support.rs | 11 + src/test/run-pass/macro-comma-behavior.rs | 98 +++++ src/test/run-pass/macro-comma-support.rs | 371 ++++++++++++++++++ 5 files changed, 601 insertions(+) create mode 100644 src/test/compile-fail/macro-comma-behavior.rs create mode 100644 src/test/compile-fail/macro-comma-support.rs create mode 100644 src/test/run-pass/auxiliary/macro-comma-support.rs create mode 100644 src/test/run-pass/macro-comma-behavior.rs create mode 100644 src/test/run-pass/macro-comma-support.rs diff --git a/src/test/compile-fail/macro-comma-behavior.rs b/src/test/compile-fail/macro-comma-behavior.rs new file mode 100644 index 0000000000000..620e57b463d1a --- /dev/null +++ b/src/test/compile-fail/macro-comma-behavior.rs @@ -0,0 +1,101 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Companion test to the similarly-named file in run-pass. + +// compile-flags: -C debug_assertions=yes +// revisions: std core + +#![cfg_attr(core, no_std)] + +#[cfg(std)] use std::fmt; +#[cfg(core)] use core::fmt; + +// (see documentation of the similarly-named test in run-pass) +fn to_format_or_not_to_format() { + let falsum = || false; + + // assert!(true, "{}",); // see run-pass + + assert_eq!(1, 1, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + assert_ne!(1, 2, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // debug_assert!(true, "{}",); // see run-pass + + debug_assert_eq!(1, 1, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + debug_assert_ne!(1, 2, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + #[cfg(std)] { + eprint!("{}",); + //[std]~^ ERROR no arguments + } + + #[cfg(std)] { + // FIXME: compile-fail says "expected error not found" even though + // rustc does emit an error + // eprintln!("{}",); + // [std]~^ ERROR no arguments + } + + #[cfg(std)] { + format!("{}",); + //[std]~^ ERROR no arguments + } + + format_args!("{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // if falsum() { panic!("{}",); } // see run-pass + + #[cfg(std)] { + print!("{}",); + //[std]~^ ERROR no arguments + } + + #[cfg(std)] { + // FIXME: compile-fail says "expected error not found" even though + // rustc does emit an error + // println!("{}",); + // [std]~^ ERROR no arguments + } + + unimplemented!("{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // if falsum() { unreachable!("{}",); } // see run-pass + + struct S; + impl fmt::Display for S { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}",)?; + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // FIXME: compile-fail says "expected error not found" even though + // rustc does emit an error + // writeln!(f, "{}",)?; + // [core]~^ ERROR no arguments + // [std]~^^ ERROR no arguments + Ok(()) + } + } +} + +fn main() {} diff --git a/src/test/compile-fail/macro-comma-support.rs b/src/test/compile-fail/macro-comma-support.rs new file mode 100644 index 0000000000000..e5fe9b4dd7f10 --- /dev/null +++ b/src/test/compile-fail/macro-comma-support.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is a companion to the similarly-named test in run-pass. +// +// It tests macros that unavoidably produce compile errors. + +fn compile_error() { + compile_error!("lel"); //~ ERROR lel + compile_error!("lel",); //~ ERROR lel +} + +fn main() {} diff --git a/src/test/run-pass/auxiliary/macro-comma-support.rs b/src/test/run-pass/auxiliary/macro-comma-support.rs new file mode 100644 index 0000000000000..6eafd520a726b --- /dev/null +++ b/src/test/run-pass/auxiliary/macro-comma-support.rs @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +() diff --git a/src/test/run-pass/macro-comma-behavior.rs b/src/test/run-pass/macro-comma-behavior.rs new file mode 100644 index 0000000000000..f8065f0ff148b --- /dev/null +++ b/src/test/run-pass/macro-comma-behavior.rs @@ -0,0 +1,98 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Ideally, any macro call with a trailing comma should behave +// identically to a call without the comma. +// +// This checks the behavior of macros with trailing commas in key +// places where regressions in behavior seem highly possible (due +// to it being e.g. a place where the addition of an argument +// causes it to go down a code path with subtly different behavior). +// +// There is a companion test in compile-fail. + +// compile-flags: --test -C debug_assertions=yes +// revisions: std core + +#![cfg_attr(core, no_std)] + +#[cfg(std)] use std::fmt; +#[cfg(core)] use core::fmt; + +// an easy mistake in the implementation of 'assert!' +// would cause this to say "explicit panic" +#[test] +#[should_panic(expected = "assertion failed")] +fn assert_1arg() { + assert!(false,); +} + +// same as 'assert_1arg' +#[test] +#[should_panic(expected = "assertion failed")] +fn debug_assert_1arg() { + debug_assert!(false,); +} + +// make sure we don't accidentally forward to `write!("text")` +#[cfg(std)] +#[test] +fn writeln_2arg() { + use fmt::Write; + + let mut s = String::new(); + writeln!(&mut s, "hi",).unwrap(); + assert_eq!(&s, "hi\n"); +} + +// A number of format_args-like macros have special-case treatment +// for a single message string, which is not formatted. +// +// This test ensures that the addition of a trailing comma does not +// suddenly cause these strings to get formatted when they otherwise +// would not be. This is an easy mistake to make by having such a macro +// accept ", $($tok:tt)*" instead of ", $($tok:tt)+" after its minimal +// set of arguments. +// +// (Example: Issue #48042) +#[test] +fn to_format_or_not_to_format() { + // ("{}" is the easiest string to test because if this gets + // sent to format_args!, it'll simply fail to compile. + // "{{}}" is an example of an input that could compile and + // produce an incorrect program, but testing the panics + // would be burdensome.) + let falsum = || false; + + assert!(true, "{}",); + + // assert_eq!(1, 1, "{}",); // see compile-fail + // assert_ne!(1, 2, "{}",); // see compile-fail + + debug_assert!(true, "{}",); + + // debug_assert_eq!(1, 1, "{}",); // see compile-fail + // debug_assert_ne!(1, 2, "{}",); // see compile-fail + // eprint!("{}",); // see compile-fail + // eprintln!("{}",); // see compile-fail + // format!("{}",); // see compile-fail + // format_args!("{}",); // see compile-fail + + if falsum() { panic!("{}",); } + + // print!("{}",); // see compile-fail + // println!("{}",); // see compile-fail + // unimplemented!("{}",); // see compile-fail + + if falsum() { unreachable!("{}",); } + + // write!(&mut stdout, "{}",); // see compile-fail + // writeln!(&mut stdout, "{}",); // see compile-fail +} diff --git a/src/test/run-pass/macro-comma-support.rs b/src/test/run-pass/macro-comma-support.rs new file mode 100644 index 0000000000000..f73dfb7b3b1d4 --- /dev/null +++ b/src/test/run-pass/macro-comma-support.rs @@ -0,0 +1,371 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is a comprehensive test of invocations with and without +// trailing commas (or other, similar optionally-trailing separators). +// Every macro is accounted for, even those not tested in this file. +// (There will be a note indicating why). +// +// The expectation is for this to be updated as new macros are added, +// or as functionality is added to existing macros. +// +// (FIXME: (please discuss in PR) is the above expectation reasonable?) + +// std and core are both tested because they may contain separate +// implementations for some macro_rules! macros as an implementation +// detail. + +// compile-flags: --test -C debug_assertions=yes +// revisions: std core + +#![cfg_attr(core, no_std)] + +#![feature(concat_idents)] + +#[cfg(std)] use std::fmt; +#[cfg(core)] use core::fmt; + +#[test] +fn assert() { + assert!(true); + assert!(true,); + assert!(true, "hello"); + assert!(true, "hello",); + assert!(true, "hello {}", "world"); + assert!(true, "hello {}", "world",); +} + +#[test] +fn assert_eq() { + assert_eq!(1, 1); + assert_eq!(1, 1,); + assert_eq!(1, 1, "hello"); + assert_eq!(1, 1, "hello",); + assert_eq!(1, 1, "hello {}", "world"); + assert_eq!(1, 1, "hello {}", "world",); +} + +#[test] +fn assert_ne() { + assert_ne!(1, 2); + assert_ne!(1, 2,); + assert_ne!(1, 2, "hello"); + assert_ne!(1, 2, "hello",); + assert_ne!(1, 2, "hello {}", "world"); + assert_ne!(1, 2, "hello {}", "world",); +} + +#[test] +fn cfg() { + let _ = cfg!(pants); + let _ = cfg!(pants,); + let _ = cfg!(pants = "pants"); + let _ = cfg!(pants = "pants",); + let _ = cfg!(all(pants)); + let _ = cfg!(all(pants),); + let _ = cfg!(all(pants,)); + let _ = cfg!(all(pants,),); +} + +#[test] +fn column() { + let _ = column!(); +} + +// compile_error! is in a companion to this test in compile-fail + +#[test] +fn concat() { + let _ = concat!(); + let _ = concat!("hello"); + let _ = concat!("hello",); + let _ = concat!("hello", " world"); + let _ = concat!("hello", " world",); +} + +#[test] +fn concat_idents() { + fn foo() {} + fn foobar() {} + + concat_idents!(foo)(); + concat_idents!(foo,)(); + concat_idents!(foo, bar)(); + concat_idents!(foo, bar,)(); +} + +#[test] +fn debug_assert() { + debug_assert!(true); + debug_assert!(true, ); + debug_assert!(true, "hello"); + debug_assert!(true, "hello",); + debug_assert!(true, "hello {}", "world"); + debug_assert!(true, "hello {}", "world",); +} + +#[test] +fn debug_assert_eq() { + debug_assert_eq!(1, 1); + debug_assert_eq!(1, 1,); + debug_assert_eq!(1, 1, "hello"); + debug_assert_eq!(1, 1, "hello",); + debug_assert_eq!(1, 1, "hello {}", "world"); + debug_assert_eq!(1, 1, "hello {}", "world",); +} + +#[test] +fn debug_assert_ne() { + debug_assert_ne!(1, 2); + debug_assert_ne!(1, 2,); + debug_assert_ne!(1, 2, "hello"); + debug_assert_ne!(1, 2, "hello",); + debug_assert_ne!(1, 2, "hello {}", "world"); + debug_assert_ne!(1, 2, "hello {}", "world",); +} + +#[test] +fn env() { + let _ = env!("PATH"); + let _ = env!("PATH",); + let _ = env!("PATH", "not found"); + let _ = env!("PATH", "not found",); +} + +#[cfg(std)] +#[test] +fn eprint() { + eprint!("hello"); + eprint!("hello",); + eprint!("hello {}", "world"); + eprint!("hello {}", "world",); +} + +#[cfg(std)] +#[test] +fn eprintln() { + eprintln!(); + eprintln!("hello"); + eprintln!("hello",); + eprintln!("hello {}", "world"); + eprintln!("hello {}", "world",); +} + +#[test] +fn file() { + let _ = file!(); +} + +#[cfg(std)] +#[test] +fn format() { + let _ = format!("hello"); + let _ = format!("hello",); + let _ = format!("hello {}", "world"); + let _ = format!("hello {}", "world",); +} + +#[test] +fn format_args() { + let _ = format_args!("hello"); + let _ = format_args!("hello",); + let _ = format_args!("hello {}", "world"); + let _ = format_args!("hello {}", "world",); +} + +#[test] +fn include() { + let _ = include!("auxiliary/macro-comma-support.rs"); + let _ = include!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn include_bytes() { + let _ = include_bytes!("auxiliary/macro-comma-support.rs"); + let _ = include_bytes!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn include_str() { + let _ = include_str!("auxiliary/macro-comma-support.rs"); + let _ = include_str!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn line() { + let _ = line!(); +} + +#[test] +fn module_path() { + let _ = module_path!(); +} + +#[test] +fn option_env() { + let _ = option_env!("PATH"); + let _ = option_env!("PATH",); +} + +#[test] +fn panic() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { panic!(); } + if falsum() { panic!("hello"); } + if falsum() { panic!("hello",); } + if falsum() { panic!("hello {}", "world"); } + if falsum() { panic!("hello {}", "world",); } +} + +#[cfg(std)] +#[test] +fn print() { + print!("hello"); + print!("hello",); + print!("hello {}", "world"); + print!("hello {}", "world",); +} + +#[cfg(std)] +#[test] +fn println() { + println!(); + println!("hello"); + println!("hello",); + println!("hello {}", "world"); + println!("hello {}", "world",); +} + +// FIXME: select! (please discuss in PR) +// +// Test cases for select! are obnoxiously large, see here: +// +// https://github.com/ExpHP/rust-macro-comma-test/blob/0062e75e01ab/src/main.rs#L190-L250 +// +// and due to other usability issues described there, it is unclear to me that it is +// going anywhere in its current state. This is a job far too big for a macro_rules! macro, +// and for as long as it exists in this form it will have many many problems far worse than +// just lack of trailing comma support. + +// stringify! is N/A + +#[cfg(std)] +#[test] +fn thread_local() { + // this has an optional trailing *semicolon* + thread_local! { + #[allow(unused)] pub static A: () = () + } + + thread_local! { + #[allow(unused)] pub static AA: () = (); + } + + thread_local! { + #[allow(unused)] pub static AAA: () = (); + #[allow(unused)] pub static AAAA: () = () + } + + thread_local! { + #[allow(unused)] pub static AAAAG: () = (); + #[allow(unused)] pub static AAAAGH: () = (); + } +} + +#[test] +fn try() { + fn inner() -> Result<(), ()> { + try!(Ok(())); + try!(Ok(()),); + Ok(()) + } + + inner().unwrap(); +} + +#[test] +fn unimplemented() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { unimplemented!(); } + if falsum() { unimplemented!("hello"); } + if falsum() { unimplemented!("hello",); } + if falsum() { unimplemented!("hello {}", "world"); } + if falsum() { unimplemented!("hello {}", "world",); } +} + +#[test] +fn unreachable() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { unreachable!(); } + if falsum() { unreachable!("hello"); } + if falsum() { unreachable!("hello",); } + if falsum() { unreachable!("hello {}", "world"); } + if falsum() { unreachable!("hello {}", "world",); } +} + +#[cfg(std)] +#[test] +fn vec() { + let _: Vec<()> = vec![]; + let _ = vec![0]; + let _ = vec![0,]; + let _ = vec![0, 1]; + let _ = vec![0, 1,]; +} + +// give a test body access to a fmt::Formatter, which seems +// to be the easiest way to use 'write!' on core. +macro_rules! test_with_formatter { + ( + #[test] + fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block + ) => { + #[test] + fn $fname() { + struct Struct; + impl fmt::Display for Struct { + fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result { + Ok($block) + } + } + + // suppress "unused" + assert!(true, "{}", Struct); + } + }; +} + +test_with_formatter! { + #[test] + fn write(f: &mut fmt::Formatter) { + let _ = write!(f, "hello"); + let _ = write!(f, "hello",); + let _ = write!(f, "hello {}", "world"); + let _ = write!(f, "hello {}", "world",); + } +} + +test_with_formatter! { + #[test] + fn writeln(f: &mut fmt::Formatter) { + let _ = writeln!(f); + let _ = writeln!(f,); + let _ = writeln!(f, "hello"); + let _ = writeln!(f, "hello",); + let _ = writeln!(f, "hello {}", "world"); + let _ = writeln!(f, "hello {}", "world",); + } +} From 96eed862a08f0ee1d234f4f83419dd46fe58ccef Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 09:31:22 -0500 Subject: [PATCH 2/5] libcore/libstd: fix commas in macro_rules! macros BREAKING CHANGE: (or perhaps, *bugfix*) In #![no_std] applications, the following calls to `panic!` used to behave differently; they now behave the same. Old behavior: panic!("{{"); // panics with "{{" panic!("{{",); // panics with "{" New behavior: panic!("{{"); // panics with "{{" panic!("{{",); // panics with "{{" This only affects calls to `panic!` (and by proxy `assert` and `debug_assert`) with a single string literal followed by a trailing comma, and only in `#![no_std]` applications. --- src/libcore/macros.rs | 17 +++++++++++++++-- src/libstd/macros.rs | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f00128a8147de..c12edaf0b29a0 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -19,7 +19,10 @@ macro_rules! panic { ($msg:expr) => ({ $crate::panicking::panic(&($msg, file!(), line!(), __rust_unstable_column!())) }); - ($fmt:expr, $($arg:tt)*) => ({ + ($msg:expr,) => ( + panic!($msg) + ); + ($fmt:expr, $($arg:tt)+) => ({ $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), &(file!(), line!(), __rust_unstable_column!())) }); @@ -79,6 +82,9 @@ macro_rules! assert { panic!(concat!("assertion failed: ", stringify!($cond))) } ); + ($cond:expr,) => ( + assert!($cond) + ); ($cond:expr, $($arg:tt)+) => ( if !$cond { panic!($($arg)+) @@ -359,7 +365,8 @@ macro_rules! try { $crate::result::Result::Err(err) => { return $crate::result::Result::Err($crate::convert::From::from(err)) } - }) + }); + ($expr:expr,) => (try!($expr)); } /// Write formatted data into a buffer. @@ -456,6 +463,9 @@ macro_rules! writeln { ($dst:expr) => ( write!($dst, "\n") ); + ($dst:expr,) => ( + writeln!($dst) + ); ($dst:expr, $fmt:expr) => ( write!($dst, concat!($fmt, "\n")) ); @@ -524,6 +534,9 @@ macro_rules! unreachable { ($msg:expr) => ({ unreachable!("{}", $msg) }); + ($msg:expr,) => ({ + unreachable!($msg) + }); ($fmt:expr, $($arg:tt)*) => ({ panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) }); diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index f058b1caef509..5a01674a3d0a0 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -68,6 +68,9 @@ macro_rules! panic { ($msg:expr) => ({ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!())) }); + ($msg:expr,) => ({ + panic!($msg) + }); ($fmt:expr, $($arg:tt)+) => ({ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), &(file!(), line!(), __rust_unstable_column!())) From 1137fb193583971f35e1d4b3cfcb25725948da4f Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 09:32:26 -0500 Subject: [PATCH 3/5] libsyntax/ext: trailing commas in builtin macros Most notably this changes 'syntax::ext::base::get_single_str_from_tts' to accept a trailing comma, and revises the documentation so that this aspect is not surprising. I made this change under the understanding that this crate is private rustc implementation detail (I hope this is correct!). After reviewing all call sites, I believe the revised semantics are closer to the intended spirit of the function. --- src/libsyntax/ext/base.rs | 6 ++++-- src/libsyntax_ext/cfg.rs | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 025aa94ce06f5..520ec942e4288 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -890,8 +890,8 @@ pub fn check_zero_tts(cx: &ExtCtxt, } } -/// Extract the string literal from the first token of `tts`. If this -/// is not a string literal, emit an error and return None. +/// Interpreting `tts` as a comma-separated sequence of expressions, +/// expect exactly one string literal, or emit an error and return None. pub fn get_single_str_from_tts(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree], @@ -903,6 +903,8 @@ pub fn get_single_str_from_tts(cx: &mut ExtCtxt, return None } let ret = panictry!(p.parse_expr()); + let _ = p.eat(&token::Comma); + if p.token != token::Eof { cx.span_err(sp, &format!("{} takes 1 argument", name)); } diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index 1d8dc4064685b..1eeba9b30b8e2 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -28,6 +28,8 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, let mut p = cx.new_parser_from_tts(tts); let cfg = panictry!(p.parse_meta_item()); + let _ = p.eat(&token::Comma); + if !p.eat(&token::Eof) { cx.span_err(sp, "expected 1 cfg-pattern"); return DummyResult::expr(sp); From b7c6dc6c0600eaee4d149c63dd3cf1faa00a098f Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 10:24:34 -0500 Subject: [PATCH 4/5] update the builtin macro doc stubs --- src/libcore/macros.rs | 25 ++++++++++++++++++++----- src/libstd/macros.rs | 25 ++++++++++++++++++++----- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c12edaf0b29a0..19bbf85cadb7c 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -616,7 +616,10 @@ mod builtin { #[stable(feature = "compile_error_macro", since = "1.20.0")] #[macro_export] #[cfg(dox)] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -652,7 +655,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -728,7 +734,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -738,7 +747,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -768,5 +780,8 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 5a01674a3d0a0..a18c811d19634 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -315,7 +315,10 @@ pub mod builtin { /// ``` #[stable(feature = "compile_error_macro", since = "1.20.0")] #[macro_export] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -403,7 +406,10 @@ pub mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -583,7 +589,10 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiรณs". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -617,7 +626,10 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiรณs". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -703,7 +715,10 @@ pub mod builtin { /// "๐Ÿ™ˆ๐Ÿ™Š๐Ÿ™‰๐Ÿ™ˆ๐Ÿ™Š๐Ÿ™‰". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } } /// A macro for defining #[cfg] if-else statements. From 9205f3d8e33fab70c89d0e283442c4b4d8b63b35 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 14 Feb 2018 02:15:27 -0500 Subject: [PATCH 5/5] macro-commas test cleanup --- src/test/run-pass/macro-comma-behavior.rs | 6 +++--- src/test/run-pass/macro-comma-support.rs | 18 ++---------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/test/run-pass/macro-comma-behavior.rs b/src/test/run-pass/macro-comma-behavior.rs index f8065f0ff148b..2a434009e134f 100644 --- a/src/test/run-pass/macro-comma-behavior.rs +++ b/src/test/run-pass/macro-comma-behavior.rs @@ -44,12 +44,12 @@ fn debug_assert_1arg() { // make sure we don't accidentally forward to `write!("text")` #[cfg(std)] #[test] -fn writeln_2arg() { +fn writeln_1arg() { use fmt::Write; let mut s = String::new(); - writeln!(&mut s, "hi",).unwrap(); - assert_eq!(&s, "hi\n"); + writeln!(&mut s,).unwrap(); + assert_eq!(&s, "\n"); } // A number of format_args-like macros have special-case treatment diff --git a/src/test/run-pass/macro-comma-support.rs b/src/test/run-pass/macro-comma-support.rs index f73dfb7b3b1d4..7d3f16728b279 100644 --- a/src/test/run-pass/macro-comma-support.rs +++ b/src/test/run-pass/macro-comma-support.rs @@ -8,15 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// This is a comprehensive test of invocations with and without +// This is meant to be a comprehensive test of invocations with/without // trailing commas (or other, similar optionally-trailing separators). // Every macro is accounted for, even those not tested in this file. // (There will be a note indicating why). -// -// The expectation is for this to be updated as new macros are added, -// or as functionality is added to existing macros. -// -// (FIXME: (please discuss in PR) is the above expectation reasonable?) // std and core are both tested because they may contain separate // implementations for some macro_rules! macros as an implementation @@ -245,16 +240,7 @@ fn println() { println!("hello {}", "world",); } -// FIXME: select! (please discuss in PR) -// -// Test cases for select! are obnoxiously large, see here: -// -// https://github.com/ExpHP/rust-macro-comma-test/blob/0062e75e01ab/src/main.rs#L190-L250 -// -// and due to other usability issues described there, it is unclear to me that it is -// going anywhere in its current state. This is a job far too big for a macro_rules! macro, -// and for as long as it exists in this form it will have many many problems far worse than -// just lack of trailing comma support. +// select! is too troublesome and unlikely to be stabilized // stringify! is N/A