]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_builtin_macros/src/format.rs
Only suggest if span is not erroneous
[rust.git] / compiler / rustc_builtin_macros / src / format.rs
1 use ArgumentType::*;
2 use Position::*;
3
4 use rustc_ast as ast;
5 use rustc_ast::ptr::P;
6 use rustc_ast::tokenstream::TokenStream;
7 use rustc_ast::visit::{self, Visitor};
8 use rustc_ast::{token, BlockCheckMode, UnsafeSource};
9 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
10 use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
11 use rustc_expand::base::{self, *};
12 use rustc_parse_format as parse;
13 use rustc_span::symbol::{sym, Ident, Symbol};
14 use rustc_span::{InnerSpan, Span};
15 use smallvec::SmallVec;
16
17 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
18 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
19 use rustc_parse_format::Count;
20 use std::borrow::Cow;
21 use std::collections::hash_map::Entry;
22
23 #[derive(PartialEq)]
24 enum ArgumentType {
25     Placeholder(&'static str),
26     Count,
27 }
28
29 enum Position {
30     Exact(usize),
31     Capture(usize),
32     Named(Symbol, InnerSpan),
33 }
34
35 struct Context<'a, 'b> {
36     ecx: &'a mut ExtCtxt<'b>,
37     /// The macro's call site. References to unstable formatting internals must
38     /// use this span to pass the stability checker.
39     macsp: Span,
40     /// The span of the format string literal.
41     fmtsp: Span,
42
43     /// List of parsed argument expressions.
44     /// Named expressions are resolved early, and are appended to the end of
45     /// argument expressions.
46     ///
47     /// Example showing the various data structures in motion:
48     ///
49     /// * Original: `"{foo:o} {:o} {foo:x} {0:x} {1:o} {:x} {1:x} {0:o}"`
50     /// * Implicit argument resolution: `"{foo:o} {0:o} {foo:x} {0:x} {1:o} {1:x} {1:x} {0:o}"`
51     /// * Name resolution: `"{2:o} {0:o} {2:x} {0:x} {1:o} {1:x} {1:x} {0:o}"`
52     /// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]`
53     /// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
54     /// * `names` (in JSON): `{"foo": 2}`
55     args: Vec<P<ast::Expr>>,
56     /// The number of arguments that were added by implicit capturing.
57     num_captured_args: usize,
58     /// Placeholder slot numbers indexed by argument.
59     arg_types: Vec<Vec<usize>>,
60     /// Unique format specs seen for each argument.
61     arg_unique_types: Vec<Vec<ArgumentType>>,
62     /// Map from named arguments to their resolved indices.
63     names: FxHashMap<Symbol, (usize, Span)>,
64
65     /// The latest consecutive literal strings, or empty if there weren't any.
66     literal: String,
67
68     /// Collection of the compiled `rt::Argument` structures
69     pieces: Vec<P<ast::Expr>>,
70     /// Collection of string literals
71     str_pieces: Vec<P<ast::Expr>>,
72     /// Stays `true` if all formatting parameters are default (as in "{}{}").
73     all_pieces_simple: bool,
74
75     /// Mapping between positional argument references and indices into the
76     /// final generated static argument array. We record the starting indices
77     /// corresponding to each positional argument, and number of references
78     /// consumed so far for each argument, to facilitate correct `Position`
79     /// mapping in `build_piece`. In effect this can be seen as a "flattened"
80     /// version of `arg_unique_types`.
81     ///
82     /// Again with the example described above in docstring for `args`:
83     ///
84     /// * `arg_index_map` (in JSON): `[[0, 1, 0], [2, 3, 3], [4, 5]]`
85     arg_index_map: Vec<Vec<usize>>,
86
87     /// Starting offset of count argument slots.
88     count_args_index_offset: usize,
89
90     /// Count argument slots and tracking data structures.
91     /// Count arguments are separately tracked for de-duplication in case
92     /// multiple references are made to one argument. For example, in this
93     /// format string:
94     ///
95     /// * Original: `"{:.*} {:.foo$} {1:.*} {:.0$}"`
96     /// * Implicit argument resolution: `"{1:.0$} {2:.foo$} {1:.3$} {4:.0$}"`
97     /// * Name resolution: `"{1:.0$} {2:.5$} {1:.3$} {4:.0$}"`
98     /// * `count_positions` (in JSON): `{0: 0, 5: 1, 3: 2}`
99     /// * `count_args`: `vec![0, 5, 3]`
100     count_args: Vec<usize>,
101     /// Relative slot numbers for count arguments.
102     count_positions: FxHashMap<usize, usize>,
103     /// Number of count slots assigned.
104     count_positions_count: usize,
105
106     /// Current position of the implicit positional arg pointer, as if it
107     /// still existed in this phase of processing.
108     /// Used only for `all_pieces_simple` tracking in `build_piece`.
109     curarg: usize,
110     /// Current piece being evaluated, used for error reporting.
111     curpiece: usize,
112     /// Keep track of invalid references to positional arguments.
113     invalid_refs: Vec<(usize, usize)>,
114     /// Spans of all the formatting arguments, in order.
115     arg_spans: Vec<Span>,
116     /// All the formatting arguments that have formatting flags set, in order for diagnostics.
117     arg_with_formatting: Vec<parse::FormatSpec<'a>>,
118
119     /// Whether this format string came from a string literal, as opposed to a macro.
120     is_literal: bool,
121 }
122
123 /// Parses the arguments from the given list of tokens, returning the diagnostic
124 /// if there's a parse error so we can continue parsing other format!
125 /// expressions.
126 ///
127 /// If parsing succeeds, the return value is:
128 ///
129 /// ```text
130 /// Some((fmtstr, parsed arguments, index map for named arguments))
131 /// ```
132 fn parse_args<'a>(
133     ecx: &mut ExtCtxt<'a>,
134     sp: Span,
135     tts: TokenStream,
136 ) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, (usize, Span)>)> {
137     let mut args = Vec::<P<ast::Expr>>::new();
138     let mut names = FxHashMap::<Symbol, (usize, Span)>::default();
139
140     let mut p = ecx.new_parser_from_tts(tts);
141
142     if p.token == token::Eof {
143         return Err(ecx.struct_span_err(sp, "requires at least a format string argument"));
144     }
145
146     let first_token = &p.token;
147     let fmtstr = match first_token.kind {
148         token::TokenKind::Literal(token::Lit {
149             kind: token::LitKind::Str | token::LitKind::StrRaw(_),
150             ..
151         }) => {
152             // If the first token is a string literal, then a format expression
153             // is constructed from it.
154             //
155             // This allows us to properly handle cases when the first comma
156             // after the format string is mistakenly replaced with any operator,
157             // which cause the expression parser to eat too much tokens.
158             p.parse_literal_maybe_minus()?
159         }
160         _ => {
161             // Otherwise, we fall back to the expression parser.
162             p.parse_expr()?
163         }
164     };
165
166     let mut first = true;
167     let mut named = false;
168
169     while p.token != token::Eof {
170         if !p.eat(&token::Comma) {
171             if first {
172                 p.clear_expected_tokens();
173             }
174
175             match p.expect(&token::Comma) {
176                 Err(mut err) => {
177                     match token::TokenKind::Comma.similar_tokens() {
178                         Some(tks) if tks.contains(&p.token.kind) => {
179                             // If a similar token is found, then it may be a typo. We
180                             // consider it as a comma, and continue parsing.
181                             err.emit();
182                             p.bump();
183                         }
184                         // Otherwise stop the parsing and return the error.
185                         _ => return Err(err),
186                     }
187                 }
188                 Ok(recovered) => {
189                     assert!(recovered);
190                 }
191             }
192         }
193         first = false;
194         if p.token == token::Eof {
195             break;
196         } // accept trailing commas
197         match p.token.ident() {
198             Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => {
199                 named = true;
200                 p.bump();
201                 p.expect(&token::Eq)?;
202                 let e = p.parse_expr()?;
203                 if let Some((prev, _)) = names.get(&ident.name) {
204                     ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
205                         .span_label(args[*prev].span, "previously here")
206                         .span_label(e.span, "duplicate argument")
207                         .emit();
208                     continue;
209                 }
210
211                 // Resolve names into slots early.
212                 // Since all the positional args are already seen at this point
213                 // if the input is valid, we can simply append to the positional
214                 // args. And remember the names.
215                 let slot = args.len();
216                 names.insert(ident.name, (slot, ident.span));
217                 args.push(e);
218             }
219             _ => {
220                 let e = p.parse_expr()?;
221                 if named {
222                     let mut err = ecx.struct_span_err(
223                         e.span,
224                         "positional arguments cannot follow named arguments",
225                     );
226                     err.span_label(e.span, "positional arguments must be before named arguments");
227                     for pos in names.values() {
228                         err.span_label(args[pos.0].span, "named argument");
229                     }
230                     err.emit();
231                 }
232                 args.push(e);
233             }
234         }
235     }
236     Ok((fmtstr, args, names))
237 }
238
239 impl<'a, 'b> Context<'a, 'b> {
240     /// The number of arguments that were explicitly given.
241     fn num_args(&self) -> usize {
242         self.args.len() - self.num_captured_args
243     }
244
245     fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
246         // NOTE: the `unwrap_or` branch is needed in case of invalid format
247         // arguments, e.g., `format_args!("{foo}")`.
248         let lookup =
249             |s: &str| self.names.get(&Symbol::intern(s)).unwrap_or(&(0, Span::default())).0;
250
251         match *p {
252             parse::String(_) => {}
253             parse::NextArgument(ref mut arg) => {
254                 if let parse::ArgumentNamed(s, _) = arg.position {
255                     arg.position = parse::ArgumentIs(lookup(s));
256                 }
257                 if let parse::CountIsName(s, _) = arg.format.width {
258                     arg.format.width = parse::CountIsParam(lookup(s));
259                 }
260                 if let parse::CountIsName(s, _) = arg.format.precision {
261                     arg.format.precision = parse::CountIsParam(lookup(s));
262                 }
263             }
264         }
265     }
266
267     /// Verifies one piece of a parse string, and remembers it if valid.
268     /// All errors are not emitted as fatal so we can continue giving errors
269     /// about this and possibly other format strings.
270     fn verify_piece(&mut self, p: &parse::Piece<'_>) {
271         match *p {
272             parse::String(..) => {}
273             parse::NextArgument(ref arg) => {
274                 // width/precision first, if they have implicit positional
275                 // parameters it makes more sense to consume them first.
276                 self.verify_count(arg.format.width);
277                 self.verify_count(arg.format.precision);
278
279                 // argument second, if it's an implicit positional parameter
280                 // it's written second, so it should come after width/precision.
281                 let pos = match arg.position {
282                     parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
283                     parse::ArgumentNamed(s, span) => {
284                         Named(Symbol::intern(s), InnerSpan::new(span.start, span.end))
285                     }
286                 };
287
288                 let ty = Placeholder(match arg.format.ty {
289                     "" => "Display",
290                     "?" => "Debug",
291                     "e" => "LowerExp",
292                     "E" => "UpperExp",
293                     "o" => "Octal",
294                     "p" => "Pointer",
295                     "b" => "Binary",
296                     "x" => "LowerHex",
297                     "X" => "UpperHex",
298                     _ => {
299                         let fmtsp = self.fmtsp;
300                         let sp = arg
301                             .format
302                             .ty_span
303                             .map(|sp| fmtsp.from_inner(InnerSpan::new(sp.start, sp.end)));
304                         let mut err = self.ecx.struct_span_err(
305                             sp.unwrap_or(fmtsp),
306                             &format!("unknown format trait `{}`", arg.format.ty),
307                         );
308                         err.note(
309                             "the only appropriate formatting traits are:\n\
310                                 - ``, which uses the `Display` trait\n\
311                                 - `?`, which uses the `Debug` trait\n\
312                                 - `e`, which uses the `LowerExp` trait\n\
313                                 - `E`, which uses the `UpperExp` trait\n\
314                                 - `o`, which uses the `Octal` trait\n\
315                                 - `p`, which uses the `Pointer` trait\n\
316                                 - `b`, which uses the `Binary` trait\n\
317                                 - `x`, which uses the `LowerHex` trait\n\
318                                 - `X`, which uses the `UpperHex` trait",
319                         );
320                         if let Some(sp) = sp {
321                             for (fmt, name) in &[
322                                 ("", "Display"),
323                                 ("?", "Debug"),
324                                 ("e", "LowerExp"),
325                                 ("E", "UpperExp"),
326                                 ("o", "Octal"),
327                                 ("p", "Pointer"),
328                                 ("b", "Binary"),
329                                 ("x", "LowerHex"),
330                                 ("X", "UpperHex"),
331                             ] {
332                                 // FIXME: rustfix (`run-rustfix`) fails to apply suggestions.
333                                 // > "Cannot replace slice of data that was already replaced"
334                                 err.tool_only_span_suggestion(
335                                     sp,
336                                     &format!("use the `{}` trait", name),
337                                     *fmt,
338                                     Applicability::MaybeIncorrect,
339                                 );
340                             }
341                         }
342                         err.emit();
343                         "<invalid>"
344                     }
345                 });
346                 self.verify_arg_type(pos, ty);
347                 self.curpiece += 1;
348             }
349         }
350     }
351
352     fn verify_count(&mut self, c: parse::Count<'_>) {
353         match c {
354             parse::CountImplied | parse::CountIs(..) => {}
355             parse::CountIsParam(i) => {
356                 self.verify_arg_type(Exact(i), Count);
357             }
358             parse::CountIsName(s, span) => {
359                 self.verify_arg_type(
360                     Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)),
361                     Count,
362                 );
363             }
364         }
365     }
366
367     fn describe_num_args(&self) -> Cow<'_, str> {
368         match self.num_args() {
369             0 => "no arguments were given".into(),
370             1 => "there is 1 argument".into(),
371             x => format!("there are {} arguments", x).into(),
372         }
373     }
374
375     /// Handle invalid references to positional arguments. Output different
376     /// errors for the case where all arguments are positional and for when
377     /// there are named arguments or numbered positional arguments in the
378     /// format string.
379     fn report_invalid_references(&self, numbered_position_args: bool) {
380         let mut e;
381         let sp = if !self.arg_spans.is_empty() {
382             // Point at the formatting arguments.
383             MultiSpan::from_spans(self.arg_spans.clone())
384         } else {
385             MultiSpan::from_span(self.fmtsp)
386         };
387         let refs =
388             self.invalid_refs.iter().map(|(r, pos)| (r.to_string(), self.arg_spans.get(*pos)));
389
390         let mut zero_based_note = false;
391
392         let count = self.pieces.len()
393             + self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
394         if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
395             e = self.ecx.struct_span_err(
396                 sp,
397                 &format!(
398                     "{} positional argument{} in format string, but {}",
399                     count,
400                     pluralize!(count),
401                     self.describe_num_args(),
402                 ),
403             );
404             for arg in &self.args {
405                 // Point at the arguments that will be formatted.
406                 e.span_label(arg.span, "");
407             }
408         } else {
409             let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip();
410             // Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)`
411             // for `println!("{7:7$}", 1);`
412             refs.sort();
413             refs.dedup();
414             let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect();
415             let sp = if self.arg_spans.is_empty() || spans.is_empty() {
416                 MultiSpan::from_span(self.fmtsp)
417             } else {
418                 MultiSpan::from_spans(spans)
419             };
420             let arg_list = if refs.len() == 1 {
421                 format!("argument {}", refs[0])
422             } else {
423                 let reg = refs.pop().unwrap();
424                 format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg)
425             };
426
427             e = self.ecx.struct_span_err(
428                 sp,
429                 &format!(
430                     "invalid reference to positional {} ({})",
431                     arg_list,
432                     self.describe_num_args()
433                 ),
434             );
435             zero_based_note = true;
436         };
437
438         for fmt in &self.arg_with_formatting {
439             if let Some(span) = fmt.precision_span {
440                 let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
441                 match fmt.precision {
442                     parse::CountIsParam(pos) if pos > self.num_args() => {
443                         e.span_label(
444                             span,
445                             &format!(
446                                 "this precision flag expects an `usize` argument at position {}, \
447                              but {}",
448                                 pos,
449                                 self.describe_num_args(),
450                             ),
451                         );
452                         zero_based_note = true;
453                     }
454                     parse::CountIsParam(pos) => {
455                         let count = self.pieces.len()
456                             + self
457                                 .arg_with_formatting
458                                 .iter()
459                                 .filter(|fmt| fmt.precision_span.is_some())
460                                 .count();
461                         e.span_label(
462                             span,
463                             &format!(
464                             "this precision flag adds an extra required argument at position {}, \
465                              which is why there {} expected",
466                             pos,
467                             if count == 1 {
468                                 "is 1 argument".to_string()
469                             } else {
470                                 format!("are {} arguments", count)
471                             },
472                         ),
473                         );
474                         if let Some(arg) = self.args.get(pos) {
475                             e.span_label(
476                                 arg.span,
477                                 "this parameter corresponds to the precision flag",
478                             );
479                         }
480                         zero_based_note = true;
481                     }
482                     _ => {}
483                 }
484             }
485             if let Some(span) = fmt.width_span {
486                 let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
487                 match fmt.width {
488                     parse::CountIsParam(pos) if pos > self.num_args() => {
489                         e.span_label(
490                             span,
491                             &format!(
492                                 "this width flag expects an `usize` argument at position {}, \
493                              but {}",
494                                 pos,
495                                 self.describe_num_args(),
496                             ),
497                         );
498                         zero_based_note = true;
499                     }
500                     _ => {}
501                 }
502             }
503         }
504         if zero_based_note {
505             e.note("positional arguments are zero-based");
506         }
507         if !self.arg_with_formatting.is_empty() {
508             e.note(
509                 "for information about formatting flags, visit \
510                     https://doc.rust-lang.org/std/fmt/index.html",
511             );
512         }
513
514         e.emit();
515     }
516
517     /// Actually verifies and tracks a given format placeholder
518     /// (a.k.a. argument).
519     fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
520         if let Exact(arg) = arg {
521             if arg >= self.num_args() {
522                 self.invalid_refs.push((arg, self.curpiece));
523                 return;
524             }
525         }
526
527         match arg {
528             Exact(arg) | Capture(arg) => {
529                 match ty {
530                     Placeholder(_) => {
531                         // record every (position, type) combination only once
532                         let seen_ty = &mut self.arg_unique_types[arg];
533                         let i = seen_ty.iter().position(|x| *x == ty).unwrap_or_else(|| {
534                             let i = seen_ty.len();
535                             seen_ty.push(ty);
536                             i
537                         });
538                         self.arg_types[arg].push(i);
539                     }
540                     Count => {
541                         if let Entry::Vacant(e) = self.count_positions.entry(arg) {
542                             let i = self.count_positions_count;
543                             e.insert(i);
544                             self.count_args.push(arg);
545                             self.count_positions_count += 1;
546                         }
547                     }
548                 }
549             }
550
551             Named(name, span) => {
552                 match self.names.get(&name) {
553                     Some(&idx) => {
554                         // Treat as positional arg.
555                         self.verify_arg_type(Capture(idx.0), ty)
556                     }
557                     None => {
558                         // For the moment capturing variables from format strings expanded from macros is
559                         // disabled (see RFC #2795)
560                         if self.is_literal {
561                             // Treat this name as a variable to capture from the surrounding scope
562                             let idx = self.args.len();
563                             self.arg_types.push(Vec::new());
564                             self.arg_unique_types.push(Vec::new());
565                             let span = if self.is_literal {
566                                 self.fmtsp.from_inner(span)
567                             } else {
568                                 self.fmtsp
569                             };
570                             self.num_captured_args += 1;
571                             self.args.push(self.ecx.expr_ident(span, Ident::new(name, span)));
572                             self.names.insert(name, (idx, span));
573                             self.verify_arg_type(Capture(idx), ty)
574                         } else {
575                             let msg = format!("there is no argument named `{}`", name);
576                             let sp = if self.is_literal {
577                                 self.fmtsp.from_inner(span)
578                             } else {
579                                 self.fmtsp
580                             };
581                             let mut err = self.ecx.struct_span_err(sp, &msg);
582
583                             err.note(&format!(
584                                 "did you intend to capture a variable `{}` from \
585                                  the surrounding scope?",
586                                 name
587                             ));
588                             err.note(
589                                 "to avoid ambiguity, `format_args!` cannot capture variables \
590                                  when the format string is expanded from a macro",
591                             );
592
593                             err.emit();
594                         }
595                     }
596                 }
597             }
598         }
599     }
600
601     /// Builds the mapping between format placeholders and argument objects.
602     fn build_index_map(&mut self) {
603         // NOTE: Keep the ordering the same as `into_expr`'s expansion would do!
604         let args_len = self.args.len();
605         self.arg_index_map.reserve(args_len);
606
607         let mut sofar = 0usize;
608
609         // Map the arguments
610         for i in 0..args_len {
611             let arg_types = &self.arg_types[i];
612             let arg_offsets = arg_types.iter().map(|offset| sofar + *offset).collect::<Vec<_>>();
613             self.arg_index_map.push(arg_offsets);
614             sofar += self.arg_unique_types[i].len();
615         }
616
617         // Record starting index for counts, which appear just after arguments
618         self.count_args_index_offset = sofar;
619     }
620
621     fn rtpath(ecx: &ExtCtxt<'_>, s: Symbol) -> Vec<Ident> {
622         ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
623     }
624
625     fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
626         let sp = self.macsp;
627         let count = |c, arg| {
628             let mut path = Context::rtpath(self.ecx, sym::Count);
629             path.push(Ident::new(c, sp));
630             match arg {
631                 Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
632                 None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
633             }
634         };
635         match c {
636             parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
637             parse::CountIsParam(i) => {
638                 // This needs mapping too, as `i` is referring to a macro
639                 // argument. If `i` is not found in `count_positions` then
640                 // the error had already been emitted elsewhere.
641                 let i = self.count_positions.get(&i).cloned().unwrap_or(0)
642                     + self.count_args_index_offset;
643                 count(sym::Param, Some(self.ecx.expr_usize(sp, i)))
644             }
645             parse::CountImplied => count(sym::Implied, None),
646             // should never be the case, names are already resolved
647             parse::CountIsName(..) => panic!("should never happen"),
648         }
649     }
650
651     /// Build a literal expression from the accumulated string literals
652     fn build_literal_string(&mut self) -> P<ast::Expr> {
653         let sp = self.fmtsp;
654         let s = Symbol::intern(&self.literal);
655         self.literal.clear();
656         self.ecx.expr_str(sp, s)
657     }
658
659     /// Builds a static `rt::Argument` from a `parse::Piece` or append
660     /// to the `literal` string.
661     fn build_piece(
662         &mut self,
663         piece: &parse::Piece<'a>,
664         arg_index_consumed: &mut Vec<usize>,
665     ) -> Option<P<ast::Expr>> {
666         let sp = self.macsp;
667         match *piece {
668             parse::String(s) => {
669                 self.literal.push_str(s);
670                 None
671             }
672             parse::NextArgument(ref arg) => {
673                 // Build the position
674                 let pos = {
675                     match arg.position {
676                         parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => {
677                             // Map to index in final generated argument array
678                             // in case of multiple types specified
679                             let arg_idx = match arg_index_consumed.get_mut(i) {
680                                 None => 0, // error already emitted elsewhere
681                                 Some(offset) => {
682                                     let idx_map = &self.arg_index_map[i];
683                                     // unwrap_or branch: error already emitted elsewhere
684                                     let arg_idx = *idx_map.get(*offset).unwrap_or(&0);
685                                     *offset += 1;
686                                     arg_idx
687                                 }
688                             };
689                             self.ecx.expr_usize(sp, arg_idx)
690                         }
691
692                         // should never be the case, because names are already
693                         // resolved.
694                         parse::ArgumentNamed(..) => panic!("should never happen"),
695                     }
696                 };
697
698                 let simple_arg = parse::Argument {
699                     position: {
700                         // We don't have ArgumentNext any more, so we have to
701                         // track the current argument ourselves.
702                         let i = self.curarg;
703                         self.curarg += 1;
704                         parse::ArgumentIs(i)
705                     },
706                     format: parse::FormatSpec {
707                         fill: arg.format.fill,
708                         align: parse::AlignUnknown,
709                         flags: 0,
710                         precision: parse::CountImplied,
711                         precision_span: None,
712                         width: parse::CountImplied,
713                         width_span: None,
714                         ty: arg.format.ty,
715                         ty_span: arg.format.ty_span,
716                     },
717                 };
718
719                 let fill = arg.format.fill.unwrap_or(' ');
720
721                 let pos_simple = arg.position.index() == simple_arg.position.index();
722
723                 if arg.format.precision_span.is_some() || arg.format.width_span.is_some() {
724                     self.arg_with_formatting.push(arg.format);
725                 }
726                 if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
727                     self.all_pieces_simple = false;
728                 }
729
730                 // Build the format
731                 let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill));
732                 let align = |name| {
733                     let mut p = Context::rtpath(self.ecx, sym::Alignment);
734                     p.push(Ident::new(name, sp));
735                     self.ecx.path_global(sp, p)
736                 };
737                 let align = match arg.format.align {
738                     parse::AlignLeft => align(sym::Left),
739                     parse::AlignRight => align(sym::Right),
740                     parse::AlignCenter => align(sym::Center),
741                     parse::AlignUnknown => align(sym::Unknown),
742                 };
743                 let align = self.ecx.expr_path(align);
744                 let flags = self.ecx.expr_u32(sp, arg.format.flags);
745                 let prec = self.build_count(arg.format.precision);
746                 let width = self.build_count(arg.format.width);
747                 let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::FormatSpec));
748                 let fmt = self.ecx.expr_struct(
749                     sp,
750                     path,
751                     vec![
752                         self.ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
753                         self.ecx.field_imm(sp, Ident::new(sym::align, sp), align),
754                         self.ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
755                         self.ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
756                         self.ecx.field_imm(sp, Ident::new(sym::width, sp), width),
757                     ],
758                 );
759
760                 let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::Argument));
761                 Some(self.ecx.expr_struct(
762                     sp,
763                     path,
764                     vec![
765                         self.ecx.field_imm(sp, Ident::new(sym::position, sp), pos),
766                         self.ecx.field_imm(sp, Ident::new(sym::format, sp), fmt),
767                     ],
768                 ))
769             }
770         }
771     }
772
773     /// Actually builds the expression which the format_args! block will be
774     /// expanded to.
775     fn into_expr(self) -> P<ast::Expr> {
776         let mut original_args = self.args;
777         let mut fmt_args = Vec::with_capacity(
778             self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
779         );
780
781         // First, build up the static array which will become our precompiled
782         // format "string"
783         let pieces = self.ecx.expr_array_ref(self.fmtsp, self.str_pieces);
784
785         // We need to construct a &[ArgumentV1] to pass into the fmt::Arguments
786         // constructor. In general the expressions in this slice might be
787         // permuted from their order in original_args (such as in the case of
788         // "{1} {0}"), or may have multiple entries referring to the same
789         // element of original_args ("{0} {0}").
790         //
791         // The following vector has one item per element of our output slice,
792         // identifying the index of which element of original_args it's passing,
793         // and that argument's type.
794         let mut fmt_arg_index_and_ty = SmallVec::<[(usize, &ArgumentType); 8]>::new();
795         for (i, unique_types) in self.arg_unique_types.iter().enumerate() {
796             fmt_arg_index_and_ty.extend(unique_types.iter().map(|ty| (i, ty)));
797         }
798         fmt_arg_index_and_ty.extend(self.count_args.iter().map(|&i| (i, &Count)));
799
800         // Figure out whether there are permuted or repeated elements. If not,
801         // we can generate simpler code.
802         //
803         // The sequence has no indices out of order or repeated if: for every
804         // adjacent pair of elements, the first one's index is less than the
805         // second one's index.
806         let nicely_ordered =
807             fmt_arg_index_and_ty.array_windows().all(|[(i, _i_ty), (j, _j_ty)]| i < j);
808
809         // We want to emit:
810         //
811         //     [ArgumentV1::new(&$arg0, â€¦), ArgumentV1::new(&$arg1, â€¦), â€¦]
812         //
813         // However, it's only legal to do so if $arg0, $arg1, â€¦ were written in
814         // exactly that order by the programmer. When arguments are permuted, we
815         // want them evaluated in the order written by the programmer, not in
816         // the order provided to fmt::Arguments. When arguments are repeated, we
817         // want the expression evaluated only once.
818         //
819         // Further, if any arg _after the first one_ contains a yield point such
820         // as `await` or `yield`, the above short form is inconvenient for the
821         // caller because it would keep a temporary of type ArgumentV1 alive
822         // across the yield point. ArgumentV1 can't implement Send since it
823         // holds a type-erased arbitrary type.
824         //
825         // Thus in the not nicely ordered case, and in the yielding case, we
826         // emit the following instead:
827         //
828         //     match (&$arg0, &$arg1, â€¦) {
829         //         args => [ArgumentV1::new(args.$i, â€¦), ArgumentV1::new(args.$j, â€¦), â€¦]
830         //     }
831         //
832         // for the sequence of indices $i, $j, â€¦ governed by fmt_arg_index_and_ty.
833         // This more verbose representation ensures that all arguments are
834         // evaluated a single time each, in the order written by the programmer,
835         // and that the surrounding future/generator (if any) is Send whenever
836         // possible.
837         let no_need_for_match =
838             nicely_ordered && !original_args.iter().skip(1).any(|e| may_contain_yield_point(e));
839
840         for (arg_index, arg_ty) in fmt_arg_index_and_ty {
841             let e = &mut original_args[arg_index];
842             let span = e.span;
843             let arg = if no_need_for_match {
844                 let expansion_span = e.span.with_ctxt(self.macsp.ctxt());
845                 // The indices are strictly ordered so e has not been taken yet.
846                 self.ecx.expr_addr_of(expansion_span, P(e.take()))
847             } else {
848                 let def_site = self.ecx.with_def_site_ctxt(span);
849                 let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::args, def_site));
850                 let member = Ident::new(sym::integer(arg_index), def_site);
851                 self.ecx.expr(def_site, ast::ExprKind::Field(args_tuple, member))
852             };
853             fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg));
854         }
855
856         let args_array = self.ecx.expr_array(self.macsp, fmt_args);
857         let args_slice = self.ecx.expr_addr_of(
858             self.macsp,
859             if no_need_for_match {
860                 args_array
861             } else {
862                 // In the !no_need_for_match case, none of the exprs were moved
863                 // away in the previous loop.
864                 //
865                 // This uses the arg span for `&arg` so that borrowck errors
866                 // point to the specific expression passed to the macro (the
867                 // span is otherwise unavailable in the MIR used by borrowck).
868                 let heads = original_args
869                     .into_iter()
870                     .map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e))
871                     .collect();
872
873                 let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp));
874                 let arm = self.ecx.arm(self.macsp, pat, args_array);
875                 let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
876                 self.ecx.expr_match(self.macsp, head, vec![arm])
877             },
878         );
879
880         // Now create the fmt::Arguments struct with all our locals we created.
881         let (fn_name, fn_args) = if self.all_pieces_simple {
882             ("new_v1", vec![pieces, args_slice])
883         } else {
884             // Build up the static array which will store our precompiled
885             // nonstandard placeholders, if there are any.
886             let fmt = self.ecx.expr_array_ref(self.macsp, self.pieces);
887
888             let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]);
889             let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new());
890             let unsafe_expr = self.ecx.expr_block(P(ast::Block {
891                 stmts: vec![self.ecx.stmt_expr(unsafe_arg)],
892                 id: ast::DUMMY_NODE_ID,
893                 rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
894                 span: self.macsp,
895                 tokens: None,
896                 could_be_bare_literal: false,
897             }));
898
899             ("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr])
900         };
901
902         let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
903         self.ecx.expr_call_global(self.macsp, path, fn_args)
904     }
905
906     fn format_arg(
907         ecx: &ExtCtxt<'_>,
908         macsp: Span,
909         mut sp: Span,
910         ty: &ArgumentType,
911         arg: P<ast::Expr>,
912     ) -> P<ast::Expr> {
913         sp = ecx.with_def_site_ctxt(sp);
914         let trait_ = match *ty {
915             Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
916             Placeholder(trait_) => trait_,
917             Count => {
918                 let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]);
919                 return ecx.expr_call_global(macsp, path, vec![arg]);
920             }
921         };
922         let new_fn_name = match trait_ {
923             "Display" => "new_display",
924             "Debug" => "new_debug",
925             "LowerExp" => "new_lower_exp",
926             "UpperExp" => "new_upper_exp",
927             "Octal" => "new_octal",
928             "Pointer" => "new_pointer",
929             "Binary" => "new_binary",
930             "LowerHex" => "new_lower_hex",
931             "UpperHex" => "new_upper_hex",
932             _ => unreachable!(),
933         };
934
935         let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]);
936         ecx.expr_call_global(sp, path, vec![arg])
937     }
938 }
939
940 fn expand_format_args_impl<'cx>(
941     ecx: &'cx mut ExtCtxt<'_>,
942     mut sp: Span,
943     tts: TokenStream,
944     nl: bool,
945 ) -> Box<dyn base::MacResult + 'cx> {
946     sp = ecx.with_def_site_ctxt(sp);
947     match parse_args(ecx, sp, tts) {
948         Ok((efmt, args, names)) => {
949             MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl))
950         }
951         Err(mut err) => {
952             err.emit();
953             DummyResult::any(sp)
954         }
955     }
956 }
957
958 pub fn expand_format_args<'cx>(
959     ecx: &'cx mut ExtCtxt<'_>,
960     sp: Span,
961     tts: TokenStream,
962 ) -> Box<dyn base::MacResult + 'cx> {
963     expand_format_args_impl(ecx, sp, tts, false)
964 }
965
966 pub fn expand_format_args_nl<'cx>(
967     ecx: &'cx mut ExtCtxt<'_>,
968     sp: Span,
969     tts: TokenStream,
970 ) -> Box<dyn base::MacResult + 'cx> {
971     expand_format_args_impl(ecx, sp, tts, true)
972 }
973
974 fn lint_named_arguments_used_positionally(
975     names: FxHashMap<Symbol, (usize, Span)>,
976     cx: &mut Context<'_, '_>,
977     unverified_pieces: Vec<parse::Piece<'_>>,
978 ) {
979     let mut used_argument_names = FxHashSet::<&str>::default();
980     for piece in unverified_pieces {
981         if let rustc_parse_format::Piece::NextArgument(a) = piece {
982             match a.position {
983                 rustc_parse_format::Position::ArgumentNamed(arg_name, _) => {
984                     used_argument_names.insert(arg_name);
985                 }
986                 _ => {}
987             };
988             if let Count::CountIsName(s, _) = a.format.width {
989                 used_argument_names.insert(s);
990             }
991             if let Count::CountIsName(s, _) = a.format.precision {
992                 used_argument_names.insert(s);
993             }
994         }
995     }
996
997     for (symbol, (index, span)) in names {
998         if !used_argument_names.contains(symbol.as_str()) {
999             let msg = format!("named argument `{}` is not used by name", symbol.as_str());
1000             let arg_span = cx.arg_spans.get(index).copied();
1001             cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
1002                 span: MultiSpan::from_span(span),
1003                 msg: msg.clone(),
1004                 node_id: ast::CRATE_NODE_ID,
1005                 lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
1006                 diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
1007                     arg_span,
1008                     span,
1009                     symbol.to_string(),
1010                 ),
1011             });
1012         }
1013     }
1014 }
1015
1016 /// Take the various parts of `format_args!(efmt, args..., name=names...)`
1017 /// and construct the appropriate formatting expression.
1018 pub fn expand_preparsed_format_args(
1019     ecx: &mut ExtCtxt<'_>,
1020     sp: Span,
1021     efmt: P<ast::Expr>,
1022     args: Vec<P<ast::Expr>>,
1023     names: FxHashMap<Symbol, (usize, Span)>,
1024     append_newline: bool,
1025 ) -> P<ast::Expr> {
1026     // NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
1027     // `ArgumentType` does not derive `Clone`.
1028     let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
1029     let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
1030
1031     let mut macsp = ecx.call_site();
1032     macsp = ecx.with_def_site_ctxt(macsp);
1033
1034     let msg = "format argument must be a string literal";
1035     let fmt_sp = efmt.span;
1036     let efmt_kind_is_lit: bool = matches!(efmt.kind, ast::ExprKind::Lit(_));
1037     let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
1038         Ok(mut fmt) if append_newline => {
1039             fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
1040             fmt
1041         }
1042         Ok(fmt) => fmt,
1043         Err(err) => {
1044             if let Some((mut err, suggested)) = err {
1045                 let sugg_fmt = match args.len() {
1046                     0 => "{}".to_string(),
1047                     _ => format!("{}{{}}", "{} ".repeat(args.len())),
1048                 };
1049                 if !suggested {
1050                     err.span_suggestion(
1051                         fmt_sp.shrink_to_lo(),
1052                         "you might be missing a string literal to format with",
1053                         format!("\"{}\", ", sugg_fmt),
1054                         Applicability::MaybeIncorrect,
1055                     );
1056                 }
1057                 err.emit();
1058             }
1059             return DummyResult::raw_expr(sp, true);
1060         }
1061     };
1062
1063     let str_style = match fmt_style {
1064         ast::StrStyle::Cooked => None,
1065         ast::StrStyle::Raw(raw) => Some(raw as usize),
1066     };
1067
1068     let fmt_str = fmt_str.as_str(); // for the suggestions below
1069     let fmt_snippet = ecx.source_map().span_to_snippet(fmt_sp).ok();
1070     let mut parser = parse::Parser::new(
1071         fmt_str,
1072         str_style,
1073         fmt_snippet,
1074         append_newline,
1075         parse::ParseMode::Format,
1076     );
1077
1078     let mut unverified_pieces = Vec::new();
1079     while let Some(piece) = parser.next() {
1080         if !parser.errors.is_empty() {
1081             break;
1082         } else {
1083             unverified_pieces.push(piece);
1084         }
1085     }
1086
1087     if !parser.errors.is_empty() {
1088         let err = parser.errors.remove(0);
1089         let sp = if efmt_kind_is_lit {
1090             fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
1091         } else {
1092             // The format string could be another macro invocation, e.g.:
1093             //     format!(concat!("abc", "{}"), 4);
1094             // However, `err.span` is an inner span relative to the *result* of
1095             // the macro invocation, which is why we would get a nonsensical
1096             // result calling `fmt_span.from_inner(err.span)` as above, and
1097             // might even end up inside a multibyte character (issue #86085).
1098             // Therefore, we conservatively report the error for the entire
1099             // argument span here.
1100             fmt_span
1101         };
1102         let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description));
1103         e.span_label(sp, err.label + " in format string");
1104         if let Some(note) = err.note {
1105             e.note(&note);
1106         }
1107         if let Some((label, span)) = err.secondary_label {
1108             if efmt_kind_is_lit {
1109                 e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
1110             }
1111         }
1112         e.emit();
1113         return DummyResult::raw_expr(sp, true);
1114     }
1115
1116     let arg_spans = parser
1117         .arg_places
1118         .iter()
1119         .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
1120         .collect();
1121
1122     let named_pos: FxHashSet<usize> = names.values().cloned().map(|(i, _)| i).collect();
1123
1124     // Clone `names` because `names` in Context get updated by verify_piece, which includes usages
1125     // of the names of named arguments, resulting in incorrect errors if a name argument is used
1126     // but not declared, such as: `println!("x = {x}");`
1127     let named_arguments = names.clone();
1128
1129     let mut cx = Context {
1130         ecx,
1131         args,
1132         num_captured_args: 0,
1133         arg_types,
1134         arg_unique_types,
1135         names,
1136         curarg: 0,
1137         curpiece: 0,
1138         arg_index_map: Vec::new(),
1139         count_args: Vec::new(),
1140         count_positions: FxHashMap::default(),
1141         count_positions_count: 0,
1142         count_args_index_offset: 0,
1143         literal: String::new(),
1144         pieces: Vec::with_capacity(unverified_pieces.len()),
1145         str_pieces: Vec::with_capacity(unverified_pieces.len()),
1146         all_pieces_simple: true,
1147         macsp,
1148         fmtsp: fmt_span,
1149         invalid_refs: Vec::new(),
1150         arg_spans,
1151         arg_with_formatting: Vec::new(),
1152         is_literal: parser.is_literal,
1153     };
1154
1155     // This needs to happen *after* the Parser has consumed all pieces to create all the spans.
1156     // unverified_pieces is used later to check named argument names are used, so clone each piece.
1157     let pieces = unverified_pieces
1158         .iter()
1159         .cloned()
1160         .map(|mut piece| {
1161             cx.verify_piece(&piece);
1162             cx.resolve_name_inplace(&mut piece);
1163             piece
1164         })
1165         .collect::<Vec<_>>();
1166
1167     let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg {
1168         parse::String(_) => false,
1169         parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)),
1170     });
1171
1172     cx.build_index_map();
1173
1174     let mut arg_index_consumed = vec![0usize; cx.arg_index_map.len()];
1175
1176     for piece in pieces {
1177         if let Some(piece) = cx.build_piece(&piece, &mut arg_index_consumed) {
1178             let s = cx.build_literal_string();
1179             cx.str_pieces.push(s);
1180             cx.pieces.push(piece);
1181         }
1182     }
1183
1184     if !cx.literal.is_empty() {
1185         let s = cx.build_literal_string();
1186         cx.str_pieces.push(s);
1187     }
1188
1189     if !cx.invalid_refs.is_empty() {
1190         cx.report_invalid_references(numbered_position_args);
1191     }
1192
1193     // Make sure that all arguments were used and all arguments have types.
1194     let errs = cx
1195         .arg_types
1196         .iter()
1197         .enumerate()
1198         .filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i))
1199         .map(|(i, _)| {
1200             let msg = if named_pos.contains(&i) {
1201                 // named argument
1202                 "named argument never used"
1203             } else {
1204                 // positional argument
1205                 "argument never used"
1206             };
1207             (cx.args[i].span, msg)
1208         })
1209         .collect::<Vec<_>>();
1210
1211     let errs_len = errs.len();
1212     if !errs.is_empty() {
1213         let args_used = cx.arg_types.len() - errs_len;
1214         let args_unused = errs_len;
1215
1216         let mut diag = {
1217             if let [(sp, msg)] = &errs[..] {
1218                 let mut diag = cx.ecx.struct_span_err(*sp, *msg);
1219                 diag.span_label(*sp, *msg);
1220                 diag
1221             } else {
1222                 let mut diag = cx.ecx.struct_span_err(
1223                     errs.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
1224                     "multiple unused formatting arguments",
1225                 );
1226                 diag.span_label(cx.fmtsp, "multiple missing formatting specifiers");
1227                 for (sp, msg) in errs {
1228                     diag.span_label(sp, msg);
1229                 }
1230                 diag
1231             }
1232         };
1233
1234         // Used to ensure we only report translations for *one* kind of foreign format.
1235         let mut found_foreign = false;
1236         // Decide if we want to look for foreign formatting directives.
1237         if args_used < args_unused {
1238             use super::format_foreign as foreign;
1239
1240             // The set of foreign substitutions we've explained.  This prevents spamming the user
1241             // with `%d should be written as {}` over and over again.
1242             let mut explained = FxHashSet::default();
1243
1244             macro_rules! check_foreign {
1245                 ($kind:ident) => {{
1246                     let mut show_doc_note = false;
1247
1248                     let mut suggestions = vec![];
1249                     // account for `"` and account for raw strings `r#`
1250                     let padding = str_style.map(|i| i + 2).unwrap_or(1);
1251                     for sub in foreign::$kind::iter_subs(fmt_str, padding) {
1252                         let (trn, success) = match sub.translate() {
1253                             Ok(trn) => (trn, true),
1254                             Err(Some(msg)) => (msg, false),
1255
1256                             // If it has no translation, don't call it out specifically.
1257                             _ => continue,
1258                         };
1259
1260                         let pos = sub.position();
1261                         let sub = String::from(sub.as_str());
1262                         if explained.contains(&sub) {
1263                             continue;
1264                         }
1265                         explained.insert(sub.clone());
1266
1267                         if !found_foreign {
1268                             found_foreign = true;
1269                             show_doc_note = true;
1270                         }
1271
1272                         if let Some(inner_sp) = pos {
1273                             let sp = fmt_sp.from_inner(inner_sp);
1274
1275                             if success {
1276                                 suggestions.push((sp, trn));
1277                             } else {
1278                                 diag.span_note(
1279                                     sp,
1280                                     &format!("format specifiers use curly braces, and {}", trn),
1281                                 );
1282                             }
1283                         } else {
1284                             if success {
1285                                 diag.help(&format!("`{}` should be written as `{}`", sub, trn));
1286                             } else {
1287                                 diag.note(&format!(
1288                                     "`{}` should use curly braces, and {}",
1289                                     sub, trn
1290                                 ));
1291                             }
1292                         }
1293                     }
1294
1295                     if show_doc_note {
1296                         diag.note(concat!(
1297                             stringify!($kind),
1298                             " formatting not supported; see the documentation for `std::fmt`",
1299                         ));
1300                     }
1301                     if suggestions.len() > 0 {
1302                         diag.multipart_suggestion(
1303                             "format specifiers use curly braces",
1304                             suggestions,
1305                             Applicability::MachineApplicable,
1306                         );
1307                     }
1308                 }};
1309             }
1310
1311             check_foreign!(printf);
1312             if !found_foreign {
1313                 check_foreign!(shell);
1314             }
1315         }
1316         if !found_foreign && errs_len == 1 {
1317             diag.span_label(cx.fmtsp, "formatting specifier missing");
1318         }
1319
1320         diag.emit();
1321     } else if cx.invalid_refs.is_empty() && !named_arguments.is_empty() {
1322         // Only check for unused named argument names if there are no other errors to avoid causing
1323         // too much noise in output errors, such as when a named argument is entirely unused.
1324         // We also only need to perform this check if there are actually named arguments.
1325         lint_named_arguments_used_positionally(named_arguments, &mut cx, unverified_pieces);
1326     }
1327
1328     cx.into_expr()
1329 }
1330
1331 fn may_contain_yield_point(e: &ast::Expr) -> bool {
1332     struct MayContainYieldPoint(bool);
1333
1334     impl Visitor<'_> for MayContainYieldPoint {
1335         fn visit_expr(&mut self, e: &ast::Expr) {
1336             if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
1337                 self.0 = true;
1338             } else {
1339                 visit::walk_expr(self, e);
1340             }
1341         }
1342
1343         fn visit_mac_call(&mut self, _: &ast::MacCall) {
1344             self.0 = true;
1345         }
1346
1347         fn visit_attribute(&mut self, _: &ast::Attribute) {
1348             // Conservatively assume this may be a proc macro attribute in
1349             // expression position.
1350             self.0 = true;
1351         }
1352
1353         fn visit_item(&mut self, _: &ast::Item) {
1354             // Do not recurse into nested items.
1355         }
1356     }
1357
1358     let mut visitor = MayContainYieldPoint(false);
1359     visitor.visit_expr(e);
1360     visitor.0
1361 }