Skip to content

Commit

Permalink
Rollup merge of rust-lang#37695 - estebank:unescaped-curly, r=alexcri…
Browse files Browse the repository at this point in the history
…chton

On fmt string with unescaped `{` note how to escape

On cases of malformed format strings where a `{` hasn't been properly escaped, like `println!("{");`, present a NOTE explaining how to escape the `{` char.

Fix rust-lang#34300.
  • Loading branch information
eddyb committed Nov 11, 2016
2 parents 2ac6f74 + 3c17abc commit 5823693
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 6 deletions.
23 changes: 19 additions & 4 deletions src/libfmt_macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ pub struct Parser<'a> {
input: &'a str,
cur: iter::Peekable<str::CharIndices<'a>>,
/// Error messages accumulated during parsing
pub errors: Vec<string::String>,
pub errors: Vec<(string::String, Option<string::String>)>,
/// Current position of implicit positional argument pointer
curarg: usize,
}
Expand All @@ -165,7 +165,9 @@ impl<'a> Iterator for Parser<'a> {
if self.consume('}') {
Some(String(self.string(pos + 1)))
} else {
self.err("unmatched `}` found");
self.err_with_note("unmatched `}` found",
"if you intended to print `}`, \
you can escape it using `}}`");
None
}
}
Expand All @@ -192,7 +194,14 @@ impl<'a> Parser<'a> {
/// String, but I think it does when this eventually uses conditions so it
/// might as well start using it now.
fn err(&mut self, msg: &str) {
self.errors.push(msg.to_owned());
self.errors.push((msg.to_owned(), None));
}

/// Notifies of an error. The message doesn't actually need to be of type
/// String, but I think it does when this eventually uses conditions so it
/// might as well start using it now.
fn err_with_note(&mut self, msg: &str, note: &str) {
self.errors.push((msg.to_owned(), Some(note.to_owned())));
}

/// Optionally consumes the specified character. If the character is not at
Expand Down Expand Up @@ -222,7 +231,13 @@ impl<'a> Parser<'a> {
self.err(&format!("expected `{:?}`, found `{:?}`", c, maybe));
}
} else {
self.err(&format!("expected `{:?}` but string was terminated", c));
let msg = &format!("expected `{:?}` but string was terminated", c);
if c == '}' {
self.err_with_note(msg,
"if you intended to print `{`, you can escape it using `{{`");
} else {
self.err(msg);
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/libsyntax_ext/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,8 +756,12 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
}

if !parser.errors.is_empty() {
cx.ecx.span_err(cx.fmtsp,
&format!("invalid format string: {}", parser.errors.remove(0)));
let (err, note) = parser.errors.remove(0);
let mut e = cx.ecx.struct_span_err(cx.fmtsp, &format!("invalid format string: {}", err));
if let Some(note) = note {
e.note(&note);
}
e.emit();
return DummyResult::raw_expr(sp);
}
if !cx.literal.is_empty() {
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/fmt/format-string-error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
println!("{");
println!("{{}}");
println!("}");
}

20 changes: 20 additions & 0 deletions src/test/ui/fmt/format-string-error.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: invalid format string: expected `'}'` but string was terminated
--> $DIR/format-string-error.rs:12:5
|
12 | println!("{");
| ^^^^^^^^^^^^^^
|
= note: if you intended to print `{`, you can escape it using `{{`
= note: this error originates in a macro outside of the current crate

error: invalid format string: unmatched `}` found
--> $DIR/format-string-error.rs:14:5
|
14 | println!("}");
| ^^^^^^^^^^^^^^
|
= note: if you intended to print `}`, you can escape it using `}}`
= note: this error originates in a macro outside of the current crate

error: aborting due to 2 previous errors

0 comments on commit 5823693

Please sign in to comment.