Skip to content

Commit

Permalink
Fix format_args capture for macro expanded format strings
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexendoo committed Sep 30, 2022
1 parent f914b82 commit 71db0dd
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 17 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ pub fn make_format_args(
append_newline: bool,
) -> Result<FormatArgs, ()> {
let msg = "format argument must be a string literal";
let fmt_span = efmt.span;
let unexpanded_fmt_span = efmt.span;
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 All @@ -174,7 +174,7 @@ pub fn make_format_args(
};
if !suggested {
err.span_suggestion(
fmt_span.shrink_to_lo(),
unexpanded_fmt_span.shrink_to_lo(),
"you might be missing a string literal to format with",
format!("\"{}\", ", sugg_fmt),
Applicability::MaybeIncorrect,
Expand All @@ -192,7 +192,7 @@ pub fn make_format_args(
};

let fmt_str = fmt_str.as_str(); // for the suggestions below
let fmt_snippet = ecx.source_map().span_to_snippet(fmt_span).ok();
let fmt_snippet = ecx.source_map().span_to_snippet(unexpanded_fmt_span).ok();
let mut parser = parse::Parser::new(
fmt_str,
str_style,
Expand Down
28 changes: 28 additions & 0 deletions src/test/ui/fmt/auxiliary/format-string-proc-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// force-host
// no-prefer-dynamic

#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::{Literal, Span, TokenStream, TokenTree};

#[proc_macro]
pub fn foo_with_input_span(input: TokenStream) -> TokenStream {
let span = input.into_iter().next().unwrap().span();

let mut lit = Literal::string("{foo}");
lit.set_span(span);

TokenStream::from(TokenTree::Literal(lit))
}

#[proc_macro]
pub fn err_with_input_span(input: TokenStream) -> TokenStream {
let span = input.into_iter().next().unwrap().span();

let mut lit = Literal::string(" }");
lit.set_span(span);

TokenStream::from(TokenTree::Literal(lit))
}
18 changes: 18 additions & 0 deletions src/test/ui/fmt/format-args-capture-macro-hygiene.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
// aux-build:format-string-proc-macro.rs

#[macro_use]
extern crate format_string_proc_macro;

macro_rules! def_site {
() => { "{foo}" } //~ ERROR: there is no argument named `foo`
}

macro_rules! call_site {
($fmt:literal) => { $fmt }
}

fn main() {
format!(concat!("{foo}")); //~ ERROR: there is no argument named `foo`
format!(concat!("{ba", "r} {}"), 1); //~ ERROR: there is no argument named `bar`

format!(def_site!());
format!(call_site!("{foo}")); //~ ERROR: there is no argument named `foo`

format!(foo_with_input_span!("")); //~ ERROR: there is no argument named `foo`
}
37 changes: 34 additions & 3 deletions src/test/ui/fmt/format-args-capture-macro-hygiene.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: there is no argument named `foo`
--> $DIR/format-args-capture-macro-hygiene.rs:2:13
--> $DIR/format-args-capture-macro-hygiene.rs:15:13
|
LL | format!(concat!("{foo}"));
| ^^^^^^^^^^^^^^^^
Expand All @@ -9,7 +9,7 @@ LL | format!(concat!("{foo}"));
= note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)

error: there is no argument named `bar`
--> $DIR/format-args-capture-macro-hygiene.rs:3:13
--> $DIR/format-args-capture-macro-hygiene.rs:16:13
|
LL | format!(concat!("{ba", "r} {}"), 1);
| ^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -18,5 +18,36 @@ LL | format!(concat!("{ba", "r} {}"), 1);
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
= note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors
error: there is no argument named `foo`
--> $DIR/format-args-capture-macro-hygiene.rs:7:13
|
LL | () => { "{foo}" }
| ^^^^^^^
...
LL | format!(def_site!());
| ----------- in this macro invocation
|
= note: did you intend to capture a variable `foo` from the surrounding scope?
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
= note: this error originates in the macro `def_site` (in Nightly builds, run with -Z macro-backtrace for more info)

error: there is no argument named `foo`
--> $DIR/format-args-capture-macro-hygiene.rs:19:24
|
LL | format!(call_site!("{foo}"));
| ^^^^^^^
|
= note: did you intend to capture a variable `foo` from the surrounding scope?
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro

error: there is no argument named `foo`
--> $DIR/format-args-capture-macro-hygiene.rs:21:34
|
LL | format!(foo_with_input_span!(""));
| ^^
|
= note: did you intend to capture a variable `foo` from the surrounding scope?
= note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro

error: aborting due to 5 previous errors

11 changes: 0 additions & 11 deletions src/test/ui/fmt/format-concat-span.stderr

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
// aux-build:format-string-proc-macro.rs

#[macro_use]
extern crate format_string_proc_macro;


// If the format string is another macro invocation, rustc would previously
// compute nonsensical spans, such as:
//
Expand All @@ -12,4 +18,7 @@
fn main() {
format!(concat!("abc}"));
//~^ ERROR: invalid format string: unmatched `}` found

format!(err_with_input_span!(""));
//~^ ERROR: invalid format string: unmatched `}` found
}
19 changes: 19 additions & 0 deletions src/test/ui/fmt/format-expanded-string.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error: invalid format string: unmatched `}` found
--> $DIR/format-expanded-string.rs:19: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: invalid format string: unmatched `}` found
--> $DIR/format-expanded-string.rs:22:34
|
LL | format!(err_with_input_span!(""));
| ^^ unmatched `}` in format string
|
= note: if you intended to print `}`, you can escape it using `}}`

error: aborting due to 2 previous errors

0 comments on commit 71db0dd

Please sign in to comment.