Skip to content

Commit

Permalink
Fix span calculation in format strings
Browse files Browse the repository at this point in the history
  • Loading branch information
FabianWolff committed Jun 7, 2021
1 parent 022720b commit 14f3ec2
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 1 deletion.
15 changes: 14 additions & 1 deletion compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,7 @@ pub fn expand_preparsed_format_args(

let msg = "format argument must be a string literal";
let fmt_sp = efmt.span;
let efmt_kind_is_lit: bool = matches!(efmt.kind, ast::ExprKind::Lit(_));
let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
Ok(mut fmt) if append_newline => {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
Expand Down Expand Up @@ -989,7 +990,19 @@ pub fn expand_preparsed_format_args(

if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
let sp = fmt_span.from_inner(err.span);
let sp = if efmt_kind_is_lit {
fmt_span.from_inner(err.span)
} else {
// The format string could be another macro invocation, e.g.:
// format!(concat!("abc", "{}"), 4);
// However, `err.span` is an inner span relative to the *result* of
// the macro invocation, which is why we would get a nonsensical
// result calling `fmt_span.from_inner(err.span)` as above, and
// might even end up inside a multibyte character (issue #86085).
// Therefore, we conservatively report the error for the entire
// argument span here.
fmt_span
};
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description));
e.span_label(sp, err.label + " in format string");
if let Some(note) = err.note {
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/fmt/format-concat-span.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// If the format string is another macro invocation, rustc would previously
// compute nonsensical spans, such as:
//
// error: invalid format string: unmatched `}` found
// --> test.rs:2:17
// |
// 2 | format!(concat!("abc}"));
// | ^ unmatched `}` in format string
//
// This test checks that this behavior has been fixed.

fn main() {
format!(concat!("abc}"));
//~^ ERROR: invalid format string: unmatched `}` found
}
11 changes: 11 additions & 0 deletions src/test/ui/fmt/format-concat-span.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: invalid format string: unmatched `}` found
--> $DIR/format-concat-span.rs:13:13
|
LL | format!(concat!("abc}"));
| ^^^^^^^^^^^^^^^ unmatched `}` in format string
|
= note: if you intended to print `}`, you can escape it using `}}`
= note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

6 changes: 6 additions & 0 deletions src/test/ui/fmt/issue-86085.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Tests for an ICE with the fuzzed input below.

fn main ( ) {
format ! ( concat ! ( r#"lJ𐏿Æ�.𐏿�"# , "r} {}" ) ) ;
//~^ ERROR: invalid format string: unmatched `}` found
}
11 changes: 11 additions & 0 deletions src/test/ui/fmt/issue-86085.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: invalid format string: unmatched `}` found
--> $DIR/issue-86085.rs:4:12
|
LL | format ! ( concat ! ( r#"lJ𐏿Æ�.𐏿�"# , "r} {}" ) ) ;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unmatched `}` in format string
|
= note: if you intended to print `}`, you can escape it using `}}`
= note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

0 comments on commit 14f3ec2

Please sign in to comment.