@@ -939,6 +939,7 @@ pub fn expand_preparsed_format_args(
939939
940940 let msg = "format argument must be a string literal" ;
941941 let fmt_sp = efmt. span ;
942+ let efmt_kind_is_lit: bool = matches ! ( efmt. kind, ast:: ExprKind :: Lit ( _) ) ;
942943 let ( fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string ( ecx, efmt, msg) {
943944 Ok ( mut fmt) if append_newline => {
944945 fmt. 0 = Symbol :: intern ( & format ! ( "{}\n " , fmt. 0 ) ) ;
@@ -989,7 +990,19 @@ pub fn expand_preparsed_format_args(
989990
990991 if !parser. errors . is_empty ( ) {
991992 let err = parser. errors . remove ( 0 ) ;
992- let sp = fmt_span. from_inner ( err. span ) ;
993+ let sp = if efmt_kind_is_lit {
994+ fmt_span. from_inner ( err. span )
995+ } else {
996+ // The format string could be another macro invocation, e.g.:
997+ // format!(concat!("abc", "{}"), 4);
998+ // However, `err.span` is an inner span relative to the *result* of
999+ // the macro invocation, which is why we would get a nonsensical
1000+ // result calling `fmt_span.from_inner(err.span)` as above, and
1001+ // might even end up inside a multibyte character (issue #86085).
1002+ // Therefore, we conservatively report the error for the entire
1003+ // argument span here.
1004+ fmt_span
1005+ } ;
9931006 let mut e = ecx. struct_span_err ( sp, & format ! ( "invalid format string: {}" , err. description) ) ;
9941007 e. span_label ( sp, err. label + " in format string" ) ;
9951008 if let Some ( note) = err. note {
0 commit comments