about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@commure.com>2018-07-19 18:53:26 -0700
committerEsteban Küber <esteban@commure.com>2018-07-19 23:18:07 -0700
commit154dee2dccd45f929b0a3d2ce2d45739513f77c8 (patch)
tree4170231db8b43d3c03f074eb1521ec7f010c2720 /src
parenta47653214f8f8561196acf25b8898e7148f1c052 (diff)
downloadrust-154dee2dccd45f929b0a3d2ce2d45739513f77c8.tar.gz
rust-154dee2dccd45f929b0a3d2ce2d45739513f77c8.zip
rework println
Diffstat (limited to 'src')
-rw-r--r--src/libfmt_macros/lib.rs6
-rw-r--r--src/libstd/macros.rs26
-rw-r--r--src/libsyntax_ext/format.rs22
-rw-r--r--src/libsyntax_ext/lib.rs10
-rw-r--r--src/test/ui/macros/trace-macro.stderr8
5 files changed, 63 insertions, 9 deletions
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 51c3efb41ad..ee590bc3b5e 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -273,7 +273,11 @@ impl<'a> Parser<'a> {
             }
         } else {
             let msg = format!("expected `{:?}` but string was terminated", c);
-            let pos = self.input.len() + 1; // point at closing `"`
+            // point at closing `"`, unless the last char is `\n` to account for `println`
+            let pos = match self.input.chars().last() {
+                Some('\n') => self.input.len(),
+                _ => self.input.len() + 1,
+            };
             if c == '}' {
                 self.err_with_note(msg,
                                    format!("expected `{:?}`", c),
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 527bab759b0..a4bcf7fd26c 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -153,9 +153,17 @@ macro_rules! print {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[allow_internal_unstable]
 macro_rules! println {
     () => (print!("\n"));
-    ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*)));
+    ($($arg:tt)*) => ({
+        #[cfg(not(stage0))] {
+            ($crate::io::_print(format_args_nl!($($arg)*)));
+        }
+        #[cfg(stage0)] {
+            print!("{}\n", format_args!($($arg)*))
+        }
+    })
 }
 
 /// Macro for printing to the standard error.
@@ -211,7 +219,8 @@ macro_rules! eprint {
 #[stable(feature = "eprint", since = "1.19.0")]
 macro_rules! eprintln {
     () => (eprint!("\n"));
-    ($($arg:tt)*) => (eprint!("{}\n", format_args!($($arg)*)));
+    ($fmt:expr) => (eprint!(concat!($fmt, "\n")));
+    ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
 }
 
 #[macro_export]
@@ -397,6 +406,19 @@ pub mod builtin {
         ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ });
     }
 
+    /// Internal version of [`format_args`].
+    ///
+    /// This macro differs from [`format_args`] in that it appends a newline to the format string
+    /// and nothing more. It is perma-unstable.
+    ///
+    /// [`format_args`]: ../std/macro.format_args.html
+    #[doc(hidden)]
+    #[unstable(feature = "println_format_args", issue="0")]
+    #[macro_export]
+    macro_rules! format_args_nl {
+        ($fmt:expr) => ({ /* compiler built-in */ });
+        ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ });
+    }
     /// Inspect an environment variable at compile time.
     ///
     /// This macro will expand to the value of the named environment variable at
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 6abf987d0ab..d3e5adf6835 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -683,7 +683,20 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt,
     sp = sp.apply_mark(ecx.current_expansion.mark);
     match parse_args(ecx, sp, tts) {
         Some((efmt, args, names)) => {
-            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names))
+            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, false))
+        }
+        None => DummyResult::expr(sp),
+    }
+}
+
+pub fn expand_format_args_nl<'cx>(ecx: &'cx mut ExtCtxt,
+                                  mut sp: Span,
+                                  tts: &[tokenstream::TokenTree])
+                                  -> Box<dyn base::MacResult + 'cx> {
+    sp = sp.apply_mark(ecx.current_expansion.mark);
+    match parse_args(ecx, sp, tts) {
+        Some((efmt, args, names)) => {
+            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, true))
         }
         None => DummyResult::expr(sp),
     }
@@ -695,7 +708,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
                                     sp: Span,
                                     efmt: P<ast::Expr>,
                                     args: Vec<P<ast::Expr>>,
-                                    names: HashMap<String, usize>)
+                                    names: HashMap<String, usize>,
+                                    append_newline: bool)
                                     -> P<ast::Expr> {
     // NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
     // `ArgumentType` does not derive `Clone`.
@@ -706,6 +720,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
     let msg = "format argument must be a string literal";
     let fmt_sp = efmt.span;
     let fmt = match expr_to_spanned_string(ecx, efmt, msg) {
+        Ok(mut fmt) if append_newline => {
+            fmt.node.0 = Symbol::intern(&format!("{}\n", fmt.node.0));
+            fmt
+        }
         Ok(fmt) => fmt,
         Err(mut err) => {
             let sugg_fmt = match args.len() {
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index bdf7a8d7040..ff76e788b3c 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -139,6 +139,16 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
                 unstable_feature: None,
                 edition: hygiene::default_edition(),
             });
+    register(Symbol::intern("format_args_nl"),
+             NormalTT {
+                 expander: Box::new(format::expand_format_args_nl),
+                 def_info: None,
+                 allow_internal_unstable: true,
+                 allow_internal_unsafe: false,
+                 local_inner_macros: false,
+                 unstable_feature: None,
+                 edition: hygiene::default_edition(),
+             });
 
     for (name, ext) in user_exts {
         register(name, ext);
diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr
index 6d8a329be80..2a30d983751 100644
--- a/src/test/ui/macros/trace-macro.stderr
+++ b/src/test/ui/macros/trace-macro.stderr
@@ -5,8 +5,8 @@ LL |     println!("Hello, World!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: expanding `println! { "Hello, World!" }`
-   = note: to `print ! ( "{}/n" , format_args ! ( "Hello, World!" ) )`
-   = note: expanding `print! { "{}/n" , format_args ! ( "Hello, World!" ) }`
-   = note: to `$crate :: io :: _print (
-           format_args ! ( "{}/n" , format_args ! ( "Hello, World!" ) ) )`
+   = note: to `{
+           # [ cfg ( not ( stage0 ) ) ] {
+           ( $crate :: io :: _print ( format_args_nl ! ( "Hello, World!" ) ) ) ; } # [
+           cfg ( stage0 ) ] { print ! ( "{}/n" , format_args ! ( "Hello, World!" ) ) } }`