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,
}
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
}
}
/// 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
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);
+ }
}
}
}
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(¬e);
+ }
+ e.emit();
return DummyResult::raw_expr(sp);
}
if !cx.literal.is_empty() {
--- /dev/null
+// 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!("}");
+}
+
--- /dev/null
+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
+