diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 51c3efb41ad97..9952e5f64d6ab 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -150,12 +150,17 @@ pub struct Parser<'a> { pub errors: Vec, /// Current position of implicit positional argument pointer curarg: usize, + /// `Some(raw count)` when the string is "raw", used to position spans correctly + style: Option, + /// How many newlines have been seen in the string so far, to adjust the error spans + seen_newlines: usize, } impl<'a> Iterator for Parser<'a> { type Item = Piece<'a>; fn next(&mut self) -> Option> { + let raw = self.style.map(|raw| raw + self.seen_newlines).unwrap_or(0); if let Some(&(pos, c)) = self.cur.peek() { match c { '{' => { @@ -170,20 +175,24 @@ impl<'a> Iterator for Parser<'a> { } '}' => { self.cur.next(); - let pos = pos + 1; if self.consume('}') { - Some(String(self.string(pos))) + Some(String(self.string(pos + 1))) } else { + let err_pos = pos + raw + 1; self.err_with_note( "unmatched `}` found", "unmatched `}`", "if you intended to print `}`, you can escape it using `}}`", - pos, - pos, + err_pos, + err_pos, ); None } } + '\n' => { + self.seen_newlines += 1; + Some(String(self.string(pos))) + } _ => Some(String(self.string(pos))), } } else { @@ -194,12 +203,14 @@ impl<'a> Iterator for Parser<'a> { impl<'a> Parser<'a> { /// Creates a new parser for the given format string - pub fn new(s: &'a str) -> Parser<'a> { + pub fn new(s: &'a str, style: Option) -> Parser<'a> { Parser { input: s, cur: s.char_indices().peekable(), errors: vec![], curarg: 0, + style, + seen_newlines: 0, } } @@ -262,24 +273,32 @@ impl<'a> Parser<'a> { /// found, an error is emitted. fn must_consume(&mut self, c: char) { self.ws(); + let raw = self.style.unwrap_or(0); + + let padding = raw + self.seen_newlines; if let Some(&(pos, maybe)) = self.cur.peek() { if c == maybe { self.cur.next(); } else { + let pos = pos + padding + 1; self.err(format!("expected `{:?}`, found `{:?}`", c, maybe), format!("expected `{}`", c), - pos + 1, - pos + 1); + pos, + pos); } } 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), "if you intended to print `{`, you can escape it using `{{`", - pos, - pos); + pos + padding, + pos + padding); } else { self.err(msg, format!("expected `{:?}`", c), pos, pos); } @@ -536,7 +555,7 @@ mod tests { use super::*; fn same(fmt: &'static str, p: &[Piece<'static>]) { - let parser = Parser::new(fmt); + let parser = Parser::new(fmt, None); assert!(parser.collect::>>() == p); } @@ -552,7 +571,7 @@ mod tests { } fn musterr(s: &str) { - let mut p = Parser::new(s); + let mut p = Parser::new(s, None); p.next(); assert!(!p.errors.is_empty()); } diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 0550cf7c6d2c0..925d3504f75fc 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -242,7 +242,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { { let name = tcx.item_name(trait_def_id); let generics = tcx.generics_of(trait_def_id); - let parser = Parser::new(&self.0); + let parser = Parser::new(&self.0, None); let mut result = Ok(()); for token in parser { match token { @@ -298,7 +298,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { Some((name, value)) }).collect::>(); - let parser = Parser::new(&self.0); + let parser = Parser::new(&self.0, None); parser.map(|p| { match p { Piece::String(s) => s, diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 75f038407c127..76f38646308d8 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -153,10 +153,17 @@ macro_rules! print { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] macro_rules! println { () => (print!("\n")); - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($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. @@ -210,10 +217,17 @@ macro_rules! eprint { /// ``` #[macro_export] #[stable(feature = "eprint", since = "1.19.0")] +#[allow_internal_unstable] macro_rules! eprintln { () => (eprint!("\n")); - ($fmt:expr) => (eprint!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); + ($($arg:tt)*) => ({ + #[cfg(all(not(stage0), not(stage1)))] { + ($crate::io::_eprint(format_args_nl!($($arg)*))); + } + #[cfg(any(stage0, stage1))] { + eprint!("{}\n", format_args!($($arg)*)) + } + }) } #[macro_export] diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 5ec44fb589818..b55c4f99206c4 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -959,29 +959,34 @@ impl<'a> ExtCtxt<'a> { /// Extract a string literal from the macro expanded version of `expr`, /// emitting `err_msg` if `expr` is not a string literal. This does not stop /// compilation on error, merely emits a non-fatal error and returns None. -pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) - -> Option> { +pub fn expr_to_spanned_string<'a>( + cx: &'a mut ExtCtxt, + expr: P, + err_msg: &str, +) -> Result, DiagnosticBuilder<'a>> { // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { expr.span = expr.span.apply_mark(cx.current_expansion.mark); expr }); - // we want to be able to handle e.g. concat("foo", "bar") + // we want to be able to handle e.g. `concat!("foo", "bar")` let expr = cx.expander().fold_expr(expr); - match expr.node { + Err(match expr.node { ast::ExprKind::Lit(ref l) => match l.node { - ast::LitKind::Str(s, style) => return Some(respan(expr.span, (s, style))), - _ => cx.span_err(l.span, err_msg) + ast::LitKind::Str(s, style) => return Ok(respan(expr.span, (s, style))), + _ => cx.struct_span_err(l.span, err_msg) }, - _ => cx.span_err(expr.span, err_msg) - } - None + _ => cx.struct_span_err(expr.span, err_msg) + }) } pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) -> Option<(Symbol, ast::StrStyle)> { - expr_to_spanned_string(cx, expr, err_msg).map(|s| s.node) + expr_to_spanned_string(cx, expr, err_msg) + .map_err(|mut err| err.emit()) + .ok() + .map(|s| s.node) } /// Non-fatally assert that `tts` is empty. Note that this function diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1241e230b26d6..4d1ca50a89375 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1592,6 +1592,7 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_trace_macros = trace_macros, fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_custom_derive = custom_derive, + fn enable_format_args_nl = format_args_nl, fn use_extern_macros_enabled = use_extern_macros, fn macros_in_extern_enabled = macros_in_extern, fn proc_macro_mod = proc_macro_mod, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0f200479fe282..5b5453d5502ab 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -129,6 +129,7 @@ declare_features! ( // rustc internal, for now: (active, intrinsics, "1.0.0", None, None), (active, lang_items, "1.0.0", None, None), + (active, format_args_nl, "1.29.0", None, None), (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), (active, linkage, "1.0.0", Some(29603), None), @@ -1327,6 +1328,9 @@ pub const EXPLAIN_LOG_SYNTAX: &'static str = pub const EXPLAIN_CONCAT_IDENTS: &'static str = "`concat_idents` is not stable enough for use and is subject to change"; +pub const EXPLAIN_FORMAT_ARGS_NL: &'static str = + "`format_args_nl` is only for internal language use and is subject to change"; + pub const EXPLAIN_TRACE_MACROS: &'static str = "`trace_macros` is not stable enough for use and is subject to change"; pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str = diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index 69b4a83764e46..99dba8af754fa 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -27,6 +27,7 @@ pub fn expand_syntax_ext( None => return base::DummyResult::expr(sp), }; let mut accumulator = String::new(); + let mut missing_literal = vec![]; for e in es { match e.node { ast::ExprKind::Lit(ref lit) => match lit.node { @@ -51,17 +52,15 @@ pub fn expand_syntax_ext( } }, _ => { - let mut err = cx.struct_span_err(e.span, "expected a literal"); - let snippet = cx.codemap().span_to_snippet(e.span).unwrap(); - err.span_suggestion( - e.span, - "you might be missing a string literal to format with", - format!("\"{{}}\", {}", snippet), - ); - err.emit(); + missing_literal.push(e.span); } } } + if missing_literal.len() > 0 { + let mut err = cx.struct_span_err(missing_literal, "expected a literal"); + err.note("only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()`"); + err.emit(); + } let sp = sp.apply_mark(cx.current_expansion.mark); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 8587d11b22786..755d2b476b716 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -17,6 +17,7 @@ use syntax::ast; use syntax::ext::base::*; use syntax::ext::base; use syntax::ext::build::AstBuilder; +use syntax::feature_gate; use syntax::parse::token; use syntax::ptr::P; use syntax::symbol::Symbol; @@ -683,7 +684,34 @@ 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 { + //if !ecx.ecfg.enable_allow_internal_unstable() { + + // For some reason, the only one that actually works for `println` is the first check + if !sp.allows_unstable() // the enclosing span is marked as `#[allow_insternal_unsable]` + && !ecx.ecfg.enable_allow_internal_unstable() // NOTE: when is this enabled? + && !ecx.ecfg.enable_format_args_nl() // enabled using `#[feature(format_args_nl]` + { + feature_gate::emit_feature_err(&ecx.parse_sess, + "format_args_nl", + sp, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_FORMAT_ARGS_NL); + return base::DummyResult::expr(sp); + } + 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 +723,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, efmt: P, args: Vec>, - names: HashMap) + names: HashMap, + append_newline: bool) -> P { // NOTE: this verbose way of initializing `Vec>` is because // `ArgumentType` does not derive `Clone`. @@ -703,10 +732,28 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let mut macsp = ecx.call_site(); macsp = macsp.apply_mark(ecx.current_expansion.mark); - let msg = "format argument must be a string literal."; + let msg = "format argument must be a string literal"; + let fmt_sp = efmt.span; let fmt = match expr_to_spanned_string(ecx, efmt, msg) { - Some(fmt) => fmt, - None => return DummyResult::raw_expr(sp), + 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() { + 0 => "{}".to_string(), + _ => format!("{}{{}}", "{} ".repeat(args.len())), + + }; + err.span_suggestion( + fmt_sp.shrink_to_lo(), + "you might be missing a string literal to format with", + format!("\"{}\", ", sugg_fmt), + ); + err.emit(); + return DummyResult::raw_expr(sp); + }, }; let mut cx = Context { @@ -731,7 +778,11 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, }; let fmt_str = &*fmt.node.0.as_str(); - let mut parser = parse::Parser::new(fmt_str); + let str_style = match fmt.node.1 { + ast::StrStyle::Cooked => None, + ast::StrStyle::Raw(raw) => Some(raw as usize), + }; + let mut parser = parse::Parser::new(fmt_str, str_style); let mut pieces = vec![]; while let Some(mut piece) = parser.next() { @@ -818,7 +869,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, errs.iter().map(|&(sp, _)| sp).collect::>(), "multiple unused formatting arguments" ); - diag.span_label(cx.fmtsp, "multiple unused arguments in this statement"); + diag.span_label(cx.fmtsp, "multiple missing formatting arguments"); diag } }; @@ -861,8 +912,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, } if show_doc_note { - diag.note(concat!(stringify!($kind), " formatting not supported; see \ - the documentation for `std::fmt`")); + diag.note(concat!( + stringify!($kind), + " formatting not supported; see the documentation for `std::fmt`", + )); } }}; } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index bdf7a8d704042..ff76e788b3c29 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/const-eval/conditional_array_execution.nll.stderr b/src/test/ui/const-eval/conditional_array_execution.nll.stderr index 8bc302a2befa4..3f82311d469ae 100644 --- a/src/test/ui/const-eval/conditional_array_execution.nll.stderr +++ b/src/test/ui/const-eval/conditional_array_execution.nll.stderr @@ -28,25 +28,19 @@ LL | println!("{}", FOO); | ^^^ referenced constant has errors error[E0080]: referenced constant has errors - --> $DIR/conditional_array_execution.rs:19:5 + --> $DIR/conditional_array_execution.rs:19:14 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; | ----- attempt to subtract with overflow ... LL | println!("{}", FOO); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^ error[E0080]: erroneous constant used - --> $DIR/conditional_array_execution.rs:19:5 + --> $DIR/conditional_array_execution.rs:19:14 | LL | println!("{}", FOO); - | ^^^^^^^^^^^^^^^---^^ - | | - | referenced constant has errors - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^ --- referenced constant has errors error[E0080]: referenced constant has errors --> $DIR/conditional_array_execution.rs:19:20 diff --git a/src/test/ui/const-eval/issue-43197.nll.stderr b/src/test/ui/const-eval/issue-43197.nll.stderr index 5819e6a9254a7..e25cb29c11475 100644 --- a/src/test/ui/const-eval/issue-43197.nll.stderr +++ b/src/test/ui/const-eval/issue-43197.nll.stderr @@ -51,25 +51,19 @@ LL | println!("{} {}", X, Y); | ^ referenced constant has errors error[E0080]: referenced constant has errors - --> $DIR/issue-43197.rs:24:5 + --> $DIR/issue-43197.rs:24:14 | LL | const X: u32 = 0-1; | --- attempt to subtract with overflow ... LL | println!("{} {}", X, Y); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^^^^ error[E0080]: erroneous constant used - --> $DIR/issue-43197.rs:24:5 + --> $DIR/issue-43197.rs:24:14 | LL | println!("{} {}", X, Y); - | ^^^^^^^^^^^^^^^^^^-^^^^^ - | | - | referenced constant has errors - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^^^^ - referenced constant has errors error[E0080]: referenced constant has errors --> $DIR/issue-43197.rs:24:26 diff --git a/src/test/ui/const-eval/issue-44578.nll.stderr b/src/test/ui/const-eval/issue-44578.nll.stderr index eeb152e00ea47..da040747991a4 100644 --- a/src/test/ui/const-eval/issue-44578.nll.stderr +++ b/src/test/ui/const-eval/issue-44578.nll.stderr @@ -1,23 +1,17 @@ error[E0080]: referenced constant has errors - --> $DIR/issue-44578.rs:35:5 + --> $DIR/issue-44578.rs:35:14 | LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; | ------------------------------------ index out of bounds: the len is 1 but the index is 1 ... LL | println!("{}", as Foo>::AMT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^ error[E0080]: erroneous constant used - --> $DIR/issue-44578.rs:35:5 + --> $DIR/issue-44578.rs:35:14 | LL | println!("{}", as Foo>::AMT); - | ^^^^^^^^^^^^^^^--------------------------^^ - | | - | referenced constant has errors - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^ -------------------------- referenced constant has errors error[E0080]: referenced constant has errors --> $DIR/issue-44578.rs:35:20 diff --git a/src/test/ui/feature-gate-format_args_nl.rs b/src/test/ui/feature-gate-format_args_nl.rs new file mode 100644 index 0000000000000..b976d57f9c179 --- /dev/null +++ b/src/test/ui/feature-gate-format_args_nl.rs @@ -0,0 +1,13 @@ +// 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. + +fn main() { + format_args_nl!(""); //~ ERROR `format_args_nl` is only for internal language use +} diff --git a/src/test/ui/feature-gate-format_args_nl.stderr b/src/test/ui/feature-gate-format_args_nl.stderr new file mode 100644 index 0000000000000..a79535641a627 --- /dev/null +++ b/src/test/ui/feature-gate-format_args_nl.stderr @@ -0,0 +1,11 @@ +error[E0658]: `format_args_nl` is only for internal language use and is subject to change + --> $DIR/feature-gate-format_args_nl.rs:12:5 + | +LL | format_args_nl!(""); //~ ERROR `format_args_nl` is only for internal language use + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(format_args_nl)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/fmt/format-string-error.rs b/src/test/ui/fmt/format-string-error.rs index 5b13686240e7c..f39110ebc5dcc 100644 --- a/src/test/ui/fmt/format-string-error.rs +++ b/src/test/ui/fmt/format-string-error.rs @@ -8,10 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-tab + fn main() { println!("{"); + //~^ ERROR invalid format string: expected `'}'` but string was terminated println!("{{}}"); println!("}"); + //~^ ERROR invalid format string: unmatched `}` found let _ = format!("{_foo}", _foo = 6usize); //~^ ERROR invalid format string: invalid argument name `_foo` let _ = format!("{_}", _ = 6usize); @@ -22,4 +26,36 @@ fn main() { //~^ ERROR invalid format string: unmatched `}` found let _ = format!("{\\}"); //~^ ERROR invalid format string: expected `'}'`, found `'\\'` + let _ = format!("\n\n\n{\n\n\n"); + //~^ ERROR invalid format string + let _ = format!(r###" + + + + {"###); + //~^ ERROR invalid format string + let _ = format!(r###" + + + + { + +"###); + //~^^ ERROR invalid format string + let _ = format!(r###" + + + + } + +"###); + //~^^^ ERROR invalid format string + let _ = format!(r###" + + + + } + +"###); + //~^^^ ERROR invalid format string: unmatched `}` found } diff --git a/src/test/ui/fmt/format-string-error.stderr b/src/test/ui/fmt/format-string-error.stderr index ff766ddc8fa67..9c84fd2521891 100644 --- a/src/test/ui/fmt/format-string-error.stderr +++ b/src/test/ui/fmt/format-string-error.stderr @@ -1,23 +1,21 @@ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/format-string-error.rs:12:5 + --> $DIR/format-string-error.rs:14:16 | LL | println!("{"); - | ^^^^^^^^^^^^^^ expected `'}'` in format string + | ^ expected `'}'` in format string | = note: if you intended to print `{`, you can escape it using `{{` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/format-string-error.rs:14:5 + --> $DIR/format-string-error.rs:17:15 | LL | println!("}"); - | ^^^^^^^^^^^^^^ unmatched `}` in format string + | ^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: invalid format string: invalid argument name `_foo` - --> $DIR/format-string-error.rs:15:23 + --> $DIR/format-string-error.rs:19:23 | LL | let _ = format!("{_foo}", _foo = 6usize); | ^^^^ invalid argument name in format string @@ -25,7 +23,7 @@ LL | let _ = format!("{_foo}", _foo = 6usize); = note: argument names cannot start with an underscore error: invalid format string: invalid argument name `_` - --> $DIR/format-string-error.rs:17:23 + --> $DIR/format-string-error.rs:21:23 | LL | let _ = format!("{_}", _ = 6usize); | ^ invalid argument name in format string @@ -33,7 +31,7 @@ LL | let _ = format!("{_}", _ = 6usize); = note: argument names cannot start with an underscore error: invalid format string: expected `'}'` but string was terminated - --> $DIR/format-string-error.rs:19:23 + --> $DIR/format-string-error.rs:23:23 | LL | let _ = format!("{"); | ^ expected `'}'` in format string @@ -41,7 +39,7 @@ LL | let _ = format!("{"); = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: unmatched `}` found - --> $DIR/format-string-error.rs:21:22 + --> $DIR/format-string-error.rs:25:22 | LL | let _ = format!("}"); | ^ unmatched `}` in format string @@ -49,10 +47,50 @@ LL | let _ = format!("}"); = note: if you intended to print `}`, you can escape it using `}}` error: invalid format string: expected `'}'`, found `'/'` - --> $DIR/format-string-error.rs:23:23 + --> $DIR/format-string-error.rs:27:23 | LL | let _ = format!("{/}"); | ^ expected `}` in format string -error: aborting due to 7 previous errors +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/format-string-error.rs:29:29 + | +LL | let _ = format!("/n/n/n{/n/n/n"); + | ^ expected `'}'` in format string + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/format-string-error.rs:35:3 + | +LL | {"###); + | ^ expected `'}'` in format string + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/format-string-error.rs:42:1 + | +LL | + | ^ expected `'}'` in format string + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: unmatched `}` found + --> $DIR/format-string-error.rs:49:2 + | +LL | } + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + +error: invalid format string: unmatched `}` found + --> $DIR/format-string-error.rs:57:9 + | +LL | } + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + +error: aborting due to 12 previous errors diff --git a/src/test/ui/issue-11692-1.stderr b/src/test/ui/issue-11692-1.stderr index daf53af3ace99..bee73e9f568b6 100644 --- a/src/test/ui/issue-11692-1.stderr +++ b/src/test/ui/issue-11692-1.stderr @@ -1,8 +1,12 @@ -error: format argument must be a string literal. +error: format argument must be a string literal --> $DIR/issue-11692-1.rs:12:12 | LL | print!(test!()); | ^^^^^^^ +help: you might be missing a string literal to format with + | +LL | print!("{}", test!()); + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/bad-concat.rs b/src/test/ui/macros/bad-concat.rs new file mode 100644 index 0000000000000..e7adee8ce8597 --- /dev/null +++ b/src/test/ui/macros/bad-concat.rs @@ -0,0 +1,18 @@ +// 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. + +fn main() { + let x: u32 = 42; + let y: f64 = 3.14; + let z = "foo"; + let _ = concat!(x, y, z, "bar"); + //~^ ERROR expected a literal + //~| NOTE only literals +} diff --git a/src/test/ui/macros/bad-concat.stderr b/src/test/ui/macros/bad-concat.stderr new file mode 100644 index 0000000000000..b97e4f268241c --- /dev/null +++ b/src/test/ui/macros/bad-concat.stderr @@ -0,0 +1,10 @@ +error: expected a literal + --> $DIR/bad-concat.rs:15:21 + | +LL | let _ = concat!(x, y, z, "bar"); + | ^ ^ ^ + | + = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()` + +error: aborting due to previous error + diff --git a/src/test/ui/macros/bad_hello.rs b/src/test/ui/macros/bad_hello.rs index 174dcc9b6cd3f..cccaf7998c98b 100644 --- a/src/test/ui/macros/bad_hello.rs +++ b/src/test/ui/macros/bad_hello.rs @@ -9,5 +9,8 @@ // except according to those terms. fn main() { - println!(3 + 4); //~ ERROR expected a literal + println!(3 + 4); + //~^ ERROR format argument must be a string literal + println!(3, 4); + //~^ ERROR format argument must be a string literal } diff --git a/src/test/ui/macros/bad_hello.stderr b/src/test/ui/macros/bad_hello.stderr index 0bfb060f84416..c675eede2152b 100644 --- a/src/test/ui/macros/bad_hello.stderr +++ b/src/test/ui/macros/bad_hello.stderr @@ -1,12 +1,22 @@ -error: expected a literal +error: format argument must be a string literal --> $DIR/bad_hello.rs:12:14 | -LL | println!(3 + 4); //~ ERROR expected a literal +LL | println!(3 + 4); | ^^^^^ help: you might be missing a string literal to format with | -LL | println!("{}", 3 + 4); //~ ERROR expected a literal - | ^^^^^^^^^^^ +LL | println!("{}", 3 + 4); + | ^^^^^ + +error: format argument must be a string literal + --> $DIR/bad_hello.rs:14:14 + | +LL | println!(3, 4); + | ^ +help: you might be missing a string literal to format with + | +LL | println!("{} {}", 3, 4); + | ^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr index 6804ce95fa873..401b2f6d67e39 100644 --- a/src/test/ui/macros/format-foreign.stderr +++ b/src/test/ui/macros/format-foreign.stderr @@ -2,12 +2,13 @@ error: multiple unused formatting arguments --> $DIR/format-foreign.rs:12:30 | LL | println!("%.*3$s %s!/n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments - | -------------------------^^^^^^^^--^^^^^^^--^-- multiple unused arguments in this statement + | -------------- ^^^^^^^^ ^^^^^^^ ^ + | | + | multiple missing formatting arguments | = help: `%.*3$s` should be written as `{:.2$}` = help: `%s` should be written as `{}` = note: printf formatting not supported; see the documentation for `std::fmt` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: argument never used --> $DIR/format-foreign.rs:13:29 diff --git a/src/test/ui/macros/format-unused-lables.stderr b/src/test/ui/macros/format-unused-lables.stderr index 777b492dcb65f..f764190438f33 100644 --- a/src/test/ui/macros/format-unused-lables.stderr +++ b/src/test/ui/macros/format-unused-lables.stderr @@ -2,24 +2,21 @@ error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:12:22 | LL | println!("Test", 123, 456, 789); - | -----------------^^^--^^^--^^^-- multiple unused arguments in this statement - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ------ ^^^ ^^^ ^^^ + | | + | multiple missing formatting arguments error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:16:9 | -LL | / println!("Test2", -LL | | 123, //~ ERROR multiple unused formatting arguments - | | ^^^ -LL | | 456, - | | ^^^ -LL | | 789 - | | ^^^ -LL | | ); - | |______- multiple unused arguments in this statement - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) +LL | println!("Test2", + | ------- multiple missing formatting arguments +LL | 123, //~ ERROR multiple unused formatting arguments + | ^^^ +LL | 456, + | ^^^ +LL | 789 + | ^^^ error: named argument never used --> $DIR/format-unused-lables.rs:21:35 @@ -30,18 +27,18 @@ LL | println!("Some stuff", UNUSED="args"); //~ ERROR named argument never u error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:24:9 | -LL | / println!("Some more $STUFF", -LL | | "woo!", //~ ERROR multiple unused formatting arguments - | | ^^^^^^ -LL | | STUFF= -LL | | "things" - | | ^^^^^^^^ -LL | | , UNUSED="args"); - | |_______________________^^^^^^_- multiple unused arguments in this statement +LL | println!("Some more $STUFF", + | ------------------ multiple missing formatting arguments +LL | "woo!", //~ ERROR multiple unused formatting arguments + | ^^^^^^ +LL | STUFF= +LL | "things" + | ^^^^^^^^ +LL | , UNUSED="args"); + | ^^^^^^ | = help: `$STUFF` should be written as `{STUFF}` = note: shell formatting not supported; see the documentation for `std::fmt` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr index 938f876872f2f..2a30d9837517e 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 ! ( concat ! ( "Hello, World!" , "/n" ) )` - = note: expanding `print! { concat ! ( "Hello, World!" , "/n" ) }` - = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( "Hello, World!" , "/n" ) ) - )` + = note: to `{ + # [ cfg ( not ( stage0 ) ) ] { + ( $crate :: io :: _print ( format_args_nl ! ( "Hello, World!" ) ) ) ; } # [ + cfg ( stage0 ) ] { print ! ( "{}/n" , format_args ! ( "Hello, World!" ) ) } }`