about summary refs log tree commit diff
path: root/src/libsyntax_ext/format.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax_ext/format.rs')
-rw-r--r--src/libsyntax_ext/format.rs1233
1 files changed, 0 insertions, 1233 deletions
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
deleted file mode 100644
index 1d1f68a4906..00000000000
--- a/src/libsyntax_ext/format.rs
+++ /dev/null
@@ -1,1233 +0,0 @@
-use ArgumentType::*;
-use Position::*;
-
-use fmt_macros as parse;
-
-use errors::pluralize;
-use errors::Applicability;
-use errors::DiagnosticBuilder;
-
-use syntax::ast;
-use syntax::ptr::P;
-use syntax::symbol::{sym, Symbol};
-use syntax::token;
-use syntax::tokenstream::TokenStream;
-use syntax_expand::base::{self, *};
-use syntax_pos::{MultiSpan, Span};
-
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use std::borrow::Cow;
-use std::collections::hash_map::Entry;
-
-#[derive(PartialEq)]
-enum ArgumentType {
-    Placeholder(&'static str),
-    Count,
-}
-
-enum Position {
-    Exact(usize),
-    Named(Symbol),
-}
-
-struct Context<'a, 'b> {
-    ecx: &'a mut ExtCtxt<'b>,
-    /// The macro's call site. References to unstable formatting internals must
-    /// use this span to pass the stability checker.
-    macsp: Span,
-    /// The span of the format string literal.
-    fmtsp: Span,
-
-    /// List of parsed argument expressions.
-    /// Named expressions are resolved early, and are appended to the end of
-    /// argument expressions.
-    ///
-    /// Example showing the various data structures in motion:
-    ///
-    /// * Original: `"{foo:o} {:o} {foo:x} {0:x} {1:o} {:x} {1:x} {0:o}"`
-    /// * Implicit argument resolution: `"{foo:o} {0:o} {foo:x} {0:x} {1:o} {1:x} {1:x} {0:o}"`
-    /// * Name resolution: `"{2:o} {0:o} {2:x} {0:x} {1:o} {1:x} {1:x} {0:o}"`
-    /// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]`
-    /// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
-    /// * `names` (in JSON): `{"foo": 2}`
-    args: Vec<P<ast::Expr>>,
-    /// Placeholder slot numbers indexed by argument.
-    arg_types: Vec<Vec<usize>>,
-    /// Unique format specs seen for each argument.
-    arg_unique_types: Vec<Vec<ArgumentType>>,
-    /// Map from named arguments to their resolved indices.
-    names: FxHashMap<Symbol, usize>,
-
-    /// The latest consecutive literal strings, or empty if there weren't any.
-    literal: String,
-
-    /// Collection of the compiled `rt::Argument` structures
-    pieces: Vec<P<ast::Expr>>,
-    /// Collection of string literals
-    str_pieces: Vec<P<ast::Expr>>,
-    /// Stays `true` if all formatting parameters are default (as in "{}{}").
-    all_pieces_simple: bool,
-
-    /// Mapping between positional argument references and indices into the
-    /// final generated static argument array. We record the starting indices
-    /// corresponding to each positional argument, and number of references
-    /// consumed so far for each argument, to facilitate correct `Position`
-    /// mapping in `build_piece`. In effect this can be seen as a "flattened"
-    /// version of `arg_unique_types`.
-    ///
-    /// Again with the example described above in docstring for `args`:
-    ///
-    /// * `arg_index_map` (in JSON): `[[0, 1, 0], [2, 3, 3], [4, 5]]`
-    arg_index_map: Vec<Vec<usize>>,
-
-    /// Starting offset of count argument slots.
-    count_args_index_offset: usize,
-
-    /// Count argument slots and tracking data structures.
-    /// Count arguments are separately tracked for de-duplication in case
-    /// multiple references are made to one argument. For example, in this
-    /// format string:
-    ///
-    /// * Original: `"{:.*} {:.foo$} {1:.*} {:.0$}"`
-    /// * Implicit argument resolution: `"{1:.0$} {2:.foo$} {1:.3$} {4:.0$}"`
-    /// * Name resolution: `"{1:.0$} {2:.5$} {1:.3$} {4:.0$}"`
-    /// * `count_positions` (in JSON): `{0: 0, 5: 1, 3: 2}`
-    /// * `count_args`: `vec![Exact(0), Exact(5), Exact(3)]`
-    count_args: Vec<Position>,
-    /// Relative slot numbers for count arguments.
-    count_positions: FxHashMap<usize, usize>,
-    /// Number of count slots assigned.
-    count_positions_count: usize,
-
-    /// Current position of the implicit positional arg pointer, as if it
-    /// still existed in this phase of processing.
-    /// Used only for `all_pieces_simple` tracking in `build_piece`.
-    curarg: usize,
-    /// Current piece being evaluated, used for error reporting.
-    curpiece: usize,
-    /// Keep track of invalid references to positional arguments.
-    invalid_refs: Vec<(usize, usize)>,
-    /// Spans of all the formatting arguments, in order.
-    arg_spans: Vec<Span>,
-    /// All the formatting arguments that have formatting flags set, in order for diagnostics.
-    arg_with_formatting: Vec<parse::FormatSpec<'a>>,
-    /// Whether this formatting string is a literal or it comes from a macro.
-    is_literal: bool,
-}
-
-/// Parses the arguments from the given list of tokens, returning the diagnostic
-/// if there's a parse error so we can continue parsing other format!
-/// expressions.
-///
-/// If parsing succeeds, the return value is:
-///
-/// ```text
-/// Some((fmtstr, parsed arguments, index map for named arguments))
-/// ```
-fn parse_args<'a>(
-    ecx: &mut ExtCtxt<'a>,
-    sp: Span,
-    tts: TokenStream,
-) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>), DiagnosticBuilder<'a>> {
-    let mut args = Vec::<P<ast::Expr>>::new();
-    let mut names = FxHashMap::<Symbol, usize>::default();
-
-    let mut p = ecx.new_parser_from_tts(tts);
-
-    if p.token == token::Eof {
-        return Err(ecx.struct_span_err(sp, "requires at least a format string argument"));
-    }
-
-    let fmtstr = p.parse_expr()?;
-    let mut first = true;
-    let mut named = false;
-
-    while p.token != token::Eof {
-        if !p.eat(&token::Comma) {
-            if first {
-                // After `format!(""` we always expect *only* a comma...
-                let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
-                err.span_label(p.token.span, "expected `,`");
-                p.maybe_annotate_with_ascription(&mut err, false);
-                return Err(err);
-            } else {
-                // ...after that delegate to `expect` to also include the other expected tokens.
-                return Err(p.expect(&token::Comma).err().unwrap());
-            }
-        }
-        first = false;
-        if p.token == token::Eof {
-            break;
-        } // accept trailing commas
-        if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) {
-            named = true;
-            let name = if let token::Ident(name, _) = p.token.kind {
-                p.bump();
-                name
-            } else {
-                unreachable!();
-            };
-
-            p.expect(&token::Eq)?;
-            let e = p.parse_expr()?;
-            if let Some(prev) = names.get(&name) {
-                ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name))
-                    .span_label(args[*prev].span, "previously here")
-                    .span_label(e.span, "duplicate argument")
-                    .emit();
-                continue;
-            }
-
-            // Resolve names into slots early.
-            // Since all the positional args are already seen at this point
-            // if the input is valid, we can simply append to the positional
-            // args. And remember the names.
-            let slot = args.len();
-            names.insert(name, slot);
-            args.push(e);
-        } else {
-            let e = p.parse_expr()?;
-            if named {
-                let mut err = ecx
-                    .struct_span_err(e.span, "positional arguments cannot follow named arguments");
-                err.span_label(e.span, "positional arguments must be before named arguments");
-                for (_, pos) in &names {
-                    err.span_label(args[*pos].span, "named argument");
-                }
-                err.emit();
-            }
-            args.push(e);
-        }
-    }
-    Ok((fmtstr, args, names))
-}
-
-impl<'a, 'b> Context<'a, 'b> {
-    fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
-        // NOTE: the `unwrap_or` branch is needed in case of invalid format
-        // arguments, e.g., `format_args!("{foo}")`.
-        let lookup = |s: Symbol| *self.names.get(&s).unwrap_or(&0);
-
-        match *p {
-            parse::String(_) => {}
-            parse::NextArgument(ref mut arg) => {
-                if let parse::ArgumentNamed(s) = arg.position {
-                    arg.position = parse::ArgumentIs(lookup(s));
-                }
-                if let parse::CountIsName(s) = arg.format.width {
-                    arg.format.width = parse::CountIsParam(lookup(s));
-                }
-                if let parse::CountIsName(s) = arg.format.precision {
-                    arg.format.precision = parse::CountIsParam(lookup(s));
-                }
-            }
-        }
-    }
-
-    /// Verifies one piece of a parse string, and remembers it if valid.
-    /// All errors are not emitted as fatal so we can continue giving errors
-    /// about this and possibly other format strings.
-    fn verify_piece(&mut self, p: &parse::Piece<'_>) {
-        match *p {
-            parse::String(..) => {}
-            parse::NextArgument(ref arg) => {
-                // width/precision first, if they have implicit positional
-                // parameters it makes more sense to consume them first.
-                self.verify_count(arg.format.width);
-                self.verify_count(arg.format.precision);
-
-                // argument second, if it's an implicit positional parameter
-                // it's written second, so it should come after width/precision.
-                let pos = match arg.position {
-                    parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
-                    parse::ArgumentNamed(s) => Named(s),
-                };
-
-                let ty = Placeholder(match &arg.format.ty[..] {
-                    "" => "Display",
-                    "?" => "Debug",
-                    "e" => "LowerExp",
-                    "E" => "UpperExp",
-                    "o" => "Octal",
-                    "p" => "Pointer",
-                    "b" => "Binary",
-                    "x" => "LowerHex",
-                    "X" => "UpperHex",
-                    _ => {
-                        let fmtsp = self.fmtsp;
-                        let sp = arg.format.ty_span.map(|sp| fmtsp.from_inner(sp));
-                        let mut err = self.ecx.struct_span_err(
-                            sp.unwrap_or(fmtsp),
-                            &format!("unknown format trait `{}`", arg.format.ty),
-                        );
-                        err.note(
-                            "the only appropriate formatting traits are:\n\
-                                - ``, which uses the `Display` trait\n\
-                                - `?`, which uses the `Debug` trait\n\
-                                - `e`, which uses the `LowerExp` trait\n\
-                                - `E`, which uses the `UpperExp` trait\n\
-                                - `o`, which uses the `Octal` trait\n\
-                                - `p`, which uses the `Pointer` trait\n\
-                                - `b`, which uses the `Binary` trait\n\
-                                - `x`, which uses the `LowerHex` trait\n\
-                                - `X`, which uses the `UpperHex` trait",
-                        );
-                        if let Some(sp) = sp {
-                            for (fmt, name) in &[
-                                ("", "Display"),
-                                ("?", "Debug"),
-                                ("e", "LowerExp"),
-                                ("E", "UpperExp"),
-                                ("o", "Octal"),
-                                ("p", "Pointer"),
-                                ("b", "Binary"),
-                                ("x", "LowerHex"),
-                                ("X", "UpperHex"),
-                            ] {
-                                err.tool_only_span_suggestion(
-                                    sp,
-                                    &format!("use the `{}` trait", name),
-                                    fmt.to_string(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                        }
-                        err.emit();
-                        "<invalid>"
-                    }
-                });
-                self.verify_arg_type(pos, ty);
-                self.curpiece += 1;
-            }
-        }
-    }
-
-    fn verify_count(&mut self, c: parse::Count) {
-        match c {
-            parse::CountImplied | parse::CountIs(..) => {}
-            parse::CountIsParam(i) => {
-                self.verify_arg_type(Exact(i), Count);
-            }
-            parse::CountIsName(s) => {
-                self.verify_arg_type(Named(s), Count);
-            }
-        }
-    }
-
-    fn describe_num_args(&self) -> Cow<'_, str> {
-        match self.args.len() {
-            0 => "no arguments were given".into(),
-            1 => "there is 1 argument".into(),
-            x => format!("there are {} arguments", x).into(),
-        }
-    }
-
-    /// Handle invalid references to positional arguments. Output different
-    /// errors for the case where all arguments are positional and for when
-    /// there are named arguments or numbered positional arguments in the
-    /// format string.
-    fn report_invalid_references(&self, numbered_position_args: bool) {
-        let mut e;
-        let sp = if self.is_literal {
-            // Point at the formatting arguments.
-            MultiSpan::from_spans(self.arg_spans.clone())
-        } else {
-            MultiSpan::from_span(self.fmtsp)
-        };
-        let refs =
-            self.invalid_refs.iter().map(|(r, pos)| (r.to_string(), self.arg_spans.get(*pos)));
-
-        let mut zero_based_note = false;
-
-        let count = self.pieces.len()
-            + self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
-        if self.names.is_empty() && !numbered_position_args && count != self.args.len() {
-            e = self.ecx.struct_span_err(
-                sp,
-                &format!(
-                    "{} positional argument{} in format string, but {}",
-                    count,
-                    pluralize!(count),
-                    self.describe_num_args(),
-                ),
-            );
-            for arg in &self.args {
-                // Point at the arguments that will be formatted.
-                e.span_label(arg.span, "");
-            }
-        } else {
-            let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip();
-            // Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)`
-            // for `println!("{7:7$}", 1);`
-            refs.sort();
-            refs.dedup();
-            let (arg_list, mut sp) = if refs.len() == 1 {
-                let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.map(|sp| *sp)).collect();
-                (
-                    format!("argument {}", refs[0]),
-                    if spans.is_empty() {
-                        MultiSpan::from_span(self.fmtsp)
-                    } else {
-                        MultiSpan::from_spans(spans)
-                    },
-                )
-            } else {
-                let pos = MultiSpan::from_spans(spans.into_iter().map(|s| *s.unwrap()).collect());
-                let reg = refs.pop().unwrap();
-                (format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg,), pos)
-            };
-            if !self.is_literal {
-                sp = MultiSpan::from_span(self.fmtsp);
-            }
-
-            e = self.ecx.struct_span_err(
-                sp,
-                &format!(
-                    "invalid reference to positional {} ({})",
-                    arg_list,
-                    self.describe_num_args()
-                ),
-            );
-            zero_based_note = true;
-        };
-
-        for fmt in &self.arg_with_formatting {
-            if let Some(span) = fmt.precision_span {
-                let span = self.fmtsp.from_inner(span);
-                match fmt.precision {
-                    parse::CountIsParam(pos) if pos > self.args.len() => {
-                        e.span_label(
-                            span,
-                            &format!(
-                                "this precision flag expects an `usize` argument at position {}, \
-                             but {}",
-                                pos,
-                                self.describe_num_args(),
-                            ),
-                        );
-                        zero_based_note = true;
-                    }
-                    parse::CountIsParam(pos) => {
-                        let count = self.pieces.len()
-                            + self
-                                .arg_with_formatting
-                                .iter()
-                                .filter(|fmt| fmt.precision_span.is_some())
-                                .count();
-                        e.span_label(span, &format!(
-                            "this precision flag adds an extra required argument at position {}, \
-                             which is why there {} expected",
-                            pos,
-                            if count == 1 {
-                                "is 1 argument".to_string()
-                            } else {
-                                format!("are {} arguments", count)
-                            },
-                        ));
-                        if let Some(arg) = self.args.get(pos) {
-                            e.span_label(
-                                arg.span,
-                                "this parameter corresponds to the precision flag",
-                            );
-                        }
-                        zero_based_note = true;
-                    }
-                    _ => {}
-                }
-            }
-            if let Some(span) = fmt.width_span {
-                let span = self.fmtsp.from_inner(span);
-                match fmt.width {
-                    parse::CountIsParam(pos) if pos > self.args.len() => {
-                        e.span_label(
-                            span,
-                            &format!(
-                                "this width flag expects an `usize` argument at position {}, \
-                             but {}",
-                                pos,
-                                self.describe_num_args(),
-                            ),
-                        );
-                        zero_based_note = true;
-                    }
-                    _ => {}
-                }
-            }
-        }
-        if zero_based_note {
-            e.note("positional arguments are zero-based");
-        }
-        if !self.arg_with_formatting.is_empty() {
-            e.note(
-                "for information about formatting flags, visit \
-                    https://doc.rust-lang.org/std/fmt/index.html",
-            );
-        }
-
-        e.emit();
-    }
-
-    /// Actually verifies and tracks a given format placeholder
-    /// (a.k.a. argument).
-    fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
-        match arg {
-            Exact(arg) => {
-                if self.args.len() <= arg {
-                    self.invalid_refs.push((arg, self.curpiece));
-                    return;
-                }
-                match ty {
-                    Placeholder(_) => {
-                        // record every (position, type) combination only once
-                        let ref mut seen_ty = self.arg_unique_types[arg];
-                        let i = seen_ty.iter().position(|x| *x == ty).unwrap_or_else(|| {
-                            let i = seen_ty.len();
-                            seen_ty.push(ty);
-                            i
-                        });
-                        self.arg_types[arg].push(i);
-                    }
-                    Count => {
-                        if let Entry::Vacant(e) = self.count_positions.entry(arg) {
-                            let i = self.count_positions_count;
-                            e.insert(i);
-                            self.count_args.push(Exact(arg));
-                            self.count_positions_count += 1;
-                        }
-                    }
-                }
-            }
-
-            Named(name) => {
-                match self.names.get(&name) {
-                    Some(&idx) => {
-                        // Treat as positional arg.
-                        self.verify_arg_type(Exact(idx), ty)
-                    }
-                    None => {
-                        let msg = format!("there is no argument named `{}`", name);
-                        let sp = if self.is_literal {
-                            *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp)
-                        } else {
-                            self.fmtsp
-                        };
-                        let mut err = self.ecx.struct_span_err(sp, &msg[..]);
-                        err.emit();
-                    }
-                }
-            }
-        }
-    }
-
-    /// Builds the mapping between format placeholders and argument objects.
-    fn build_index_map(&mut self) {
-        // NOTE: Keep the ordering the same as `into_expr`'s expansion would do!
-        let args_len = self.args.len();
-        self.arg_index_map.reserve(args_len);
-
-        let mut sofar = 0usize;
-
-        // Map the arguments
-        for i in 0..args_len {
-            let ref arg_types = self.arg_types[i];
-            let arg_offsets = arg_types.iter().map(|offset| sofar + *offset).collect::<Vec<_>>();
-            self.arg_index_map.push(arg_offsets);
-            sofar += self.arg_unique_types[i].len();
-        }
-
-        // Record starting index for counts, which appear just after arguments
-        self.count_args_index_offset = sofar;
-    }
-
-    fn rtpath(ecx: &ExtCtxt<'_>, s: &str) -> Vec<ast::Ident> {
-        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)])
-    }
-
-    fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
-        let sp = self.macsp;
-        let count = |c, arg| {
-            let mut path = Context::rtpath(self.ecx, "Count");
-            path.push(self.ecx.ident_of(c, sp));
-            match arg {
-                Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
-                None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
-            }
-        };
-        match c {
-            parse::CountIs(i) => count("Is", Some(self.ecx.expr_usize(sp, i))),
-            parse::CountIsParam(i) => {
-                // This needs mapping too, as `i` is referring to a macro
-                // argument. If `i` is not found in `count_positions` then
-                // the error had already been emitted elsewhere.
-                let i = self.count_positions.get(&i).cloned().unwrap_or(0)
-                    + self.count_args_index_offset;
-                count("Param", Some(self.ecx.expr_usize(sp, i)))
-            }
-            parse::CountImplied => count("Implied", None),
-            // should never be the case, names are already resolved
-            parse::CountIsName(_) => panic!("should never happen"),
-        }
-    }
-
-    /// Build a literal expression from the accumulated string literals
-    fn build_literal_string(&mut self) -> P<ast::Expr> {
-        let sp = self.fmtsp;
-        let s = Symbol::intern(&self.literal);
-        self.literal.clear();
-        self.ecx.expr_str(sp, s)
-    }
-
-    /// Builds a static `rt::Argument` from a `parse::Piece` or append
-    /// to the `literal` string.
-    fn build_piece(
-        &mut self,
-        piece: &parse::Piece<'a>,
-        arg_index_consumed: &mut Vec<usize>,
-    ) -> Option<P<ast::Expr>> {
-        let sp = self.macsp;
-        match *piece {
-            parse::String(s) => {
-                self.literal.push_str(s);
-                None
-            }
-            parse::NextArgument(ref arg) => {
-                // Build the position
-                let pos = {
-                    let pos = |c, arg| {
-                        let mut path = Context::rtpath(self.ecx, "Position");
-                        path.push(self.ecx.ident_of(c, sp));
-                        match arg {
-                            Some(i) => {
-                                let arg = self.ecx.expr_usize(sp, i);
-                                self.ecx.expr_call_global(sp, path, vec![arg])
-                            }
-                            None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
-                        }
-                    };
-                    match arg.position {
-                        parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => {
-                            // Map to index in final generated argument array
-                            // in case of multiple types specified
-                            let arg_idx = match arg_index_consumed.get_mut(i) {
-                                None => 0, // error already emitted elsewhere
-                                Some(offset) => {
-                                    let ref idx_map = self.arg_index_map[i];
-                                    // unwrap_or branch: error already emitted elsewhere
-                                    let arg_idx = *idx_map.get(*offset).unwrap_or(&0);
-                                    *offset += 1;
-                                    arg_idx
-                                }
-                            };
-                            pos("At", Some(arg_idx))
-                        }
-
-                        // should never be the case, because names are already
-                        // resolved.
-                        parse::ArgumentNamed(_) => panic!("should never happen"),
-                    }
-                };
-
-                let simple_arg = parse::Argument {
-                    position: {
-                        // We don't have ArgumentNext any more, so we have to
-                        // track the current argument ourselves.
-                        let i = self.curarg;
-                        self.curarg += 1;
-                        parse::ArgumentIs(i)
-                    },
-                    format: parse::FormatSpec {
-                        fill: arg.format.fill,
-                        align: parse::AlignUnknown,
-                        flags: 0,
-                        precision: parse::CountImplied,
-                        precision_span: None,
-                        width: parse::CountImplied,
-                        width_span: None,
-                        ty: arg.format.ty,
-                        ty_span: arg.format.ty_span,
-                    },
-                };
-
-                let fill = arg.format.fill.unwrap_or(' ');
-
-                let pos_simple = arg.position.index() == simple_arg.position.index();
-
-                if arg.format.precision_span.is_some() || arg.format.width_span.is_some() {
-                    self.arg_with_formatting.push(arg.format);
-                }
-                if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
-                    self.all_pieces_simple = false;
-                }
-
-                // Build the format
-                let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill));
-                let align = |name| {
-                    let mut p = Context::rtpath(self.ecx, "Alignment");
-                    p.push(self.ecx.ident_of(name, sp));
-                    self.ecx.path_global(sp, p)
-                };
-                let align = match arg.format.align {
-                    parse::AlignLeft => align("Left"),
-                    parse::AlignRight => align("Right"),
-                    parse::AlignCenter => align("Center"),
-                    parse::AlignUnknown => align("Unknown"),
-                };
-                let align = self.ecx.expr_path(align);
-                let flags = self.ecx.expr_u32(sp, arg.format.flags);
-                let prec = self.build_count(arg.format.precision);
-                let width = self.build_count(arg.format.width);
-                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec"));
-                let fmt = self.ecx.expr_struct(
-                    sp,
-                    path,
-                    vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("fill", sp), fill),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("align", sp), align),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("flags", sp), flags),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("precision", sp), prec),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("width", sp), width),
-                    ],
-                );
-
-                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "Argument"));
-                Some(self.ecx.expr_struct(
-                    sp,
-                    path,
-                    vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("position", sp), pos),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("format", sp), fmt),
-                    ],
-                ))
-            }
-        }
-    }
-
-    /// Actually builds the expression which the format_args! block will be
-    /// expanded to.
-    fn into_expr(self) -> P<ast::Expr> {
-        let mut locals =
-            Vec::with_capacity((0..self.args.len()).map(|i| self.arg_unique_types[i].len()).sum());
-        let mut counts = Vec::with_capacity(self.count_args.len());
-        let mut pats = Vec::with_capacity(self.args.len());
-        let mut heads = Vec::with_capacity(self.args.len());
-
-        let names_pos: Vec<_> = (0..self.args.len())
-            .map(|i| self.ecx.ident_of(&format!("arg{}", i), self.macsp))
-            .collect();
-
-        // First, build up the static array which will become our precompiled
-        // format "string"
-        let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
-
-        // Before consuming the expressions, we have to remember spans for
-        // count arguments as they are now generated separate from other
-        // arguments, hence have no access to the `P<ast::Expr>`'s.
-        let spans_pos: Vec<_> = self.args.iter().map(|e| e.span.clone()).collect();
-
-        // Right now there is a bug such that for the expression:
-        //      foo(bar(&1))
-        // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
-        // valid for the call to `foo`. To work around this all arguments to the
-        // format! string are shoved into locals. Furthermore, we shove the address
-        // of each variable because we don't want to move out of the arguments
-        // passed to this function.
-        for (i, e) in self.args.into_iter().enumerate() {
-            let name = names_pos[i];
-            let span = self.ecx.with_def_site_ctxt(e.span);
-            pats.push(self.ecx.pat_ident(span, name));
-            for ref arg_ty in self.arg_unique_types[i].iter() {
-                locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name));
-            }
-            heads.push(self.ecx.expr_addr_of(e.span, e));
-        }
-        for pos in self.count_args {
-            let index = match pos {
-                Exact(i) => i,
-                _ => panic!("should never happen"),
-            };
-            let name = names_pos[index];
-            let span = spans_pos[index];
-            counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name));
-        }
-
-        // Now create a vector containing all the arguments
-        let args = locals.into_iter().chain(counts.into_iter());
-
-        let args_array = self.ecx.expr_vec(self.macsp, args.collect());
-
-        // Constructs an AST equivalent to:
-        //
-        //      match (&arg0, &arg1) {
-        //          (tmp0, tmp1) => args_array
-        //      }
-        //
-        // It was:
-        //
-        //      let tmp0 = &arg0;
-        //      let tmp1 = &arg1;
-        //      args_array
-        //
-        // Because of #11585 the new temporary lifetime rule, the enclosing
-        // statements for these temporaries become the let's themselves.
-        // If one or more of them are RefCell's, RefCell borrow() will also
-        // end there; they don't last long enough for args_array to use them.
-        // The match expression solves the scope problem.
-        //
-        // Note, it may also very well be transformed to:
-        //
-        //      match arg0 {
-        //          ref tmp0 => {
-        //              match arg1 => {
-        //                  ref tmp1 => args_array } } }
-        //
-        // But the nested match expression is proved to perform not as well
-        // as series of let's; the first approach does.
-        let pat = self.ecx.pat_tuple(self.macsp, pats);
-        let arm = self.ecx.arm(self.macsp, pat, args_array);
-        let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
-        let result = self.ecx.expr_match(self.macsp, head, vec![arm]);
-
-        let args_slice = self.ecx.expr_addr_of(self.macsp, result);
-
-        // Now create the fmt::Arguments struct with all our locals we created.
-        let (fn_name, fn_args) = if self.all_pieces_simple {
-            ("new_v1", vec![pieces, args_slice])
-        } else {
-            // Build up the static array which will store our precompiled
-            // nonstandard placeholders, if there are any.
-            let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces);
-
-            ("new_v1_formatted", vec![pieces, args_slice, fmt])
-        };
-
-        let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
-        self.ecx.expr_call_global(self.macsp, path, fn_args)
-    }
-
-    fn format_arg(
-        ecx: &ExtCtxt<'_>,
-        macsp: Span,
-        mut sp: Span,
-        ty: &ArgumentType,
-        arg: ast::Ident,
-    ) -> P<ast::Expr> {
-        sp = ecx.with_def_site_ctxt(sp);
-        let arg = ecx.expr_ident(sp, arg);
-        let trait_ = match *ty {
-            Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
-            Placeholder(trait_) => trait_,
-            Count => {
-                let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]);
-                return ecx.expr_call_global(macsp, path, vec![arg]);
-            }
-        };
-
-        let path = ecx.std_path(&[sym::fmt, Symbol::intern(trait_), sym::fmt]);
-        let format_fn = ecx.path_global(sp, path);
-        let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::new]);
-        ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)])
-    }
-}
-
-fn expand_format_args_impl<'cx>(
-    ecx: &'cx mut ExtCtxt<'_>,
-    mut sp: Span,
-    tts: TokenStream,
-    nl: bool,
-) -> Box<dyn base::MacResult + 'cx> {
-    sp = ecx.with_def_site_ctxt(sp);
-    match parse_args(ecx, sp, tts) {
-        Ok((efmt, args, names)) => {
-            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl))
-        }
-        Err(mut err) => {
-            err.emit();
-            DummyResult::any(sp)
-        }
-    }
-}
-
-pub fn expand_format_args<'cx>(
-    ecx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    expand_format_args_impl(ecx, sp, tts, false)
-}
-
-pub fn expand_format_args_nl<'cx>(
-    ecx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    expand_format_args_impl(ecx, sp, tts, true)
-}
-
-/// Take the various parts of `format_args!(efmt, args..., name=names...)`
-/// and construct the appropriate formatting expression.
-pub fn expand_preparsed_format_args(
-    ecx: &mut ExtCtxt<'_>,
-    sp: Span,
-    efmt: P<ast::Expr>,
-    args: Vec<P<ast::Expr>>,
-    names: FxHashMap<Symbol, usize>,
-    append_newline: bool,
-) -> P<ast::Expr> {
-    // NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
-    // `ArgumentType` does not derive `Clone`.
-    let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
-    let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
-
-    let mut macsp = ecx.call_site();
-    macsp = ecx.with_def_site_ctxt(macsp);
-
-    let msg = "format argument must be a string literal";
-    let fmt_sp = 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));
-            fmt
-        }
-        Ok(fmt) => fmt,
-        Err(err) => {
-            if let Some(mut err) = err {
-                let sugg_fmt = match args.len() {
-                    0 => "{}".to_string(),
-                    _ => format!("{}{{}}", "{} ".repeat(args.len())),
-                };
-                err.span_suggestion(
-                    fmt_sp.shrink_to_lo(),
-                    "you might be missing a string literal to format with",
-                    format!("\"{}\", ", sugg_fmt),
-                    Applicability::MaybeIncorrect,
-                );
-                err.emit();
-            }
-            return DummyResult::raw_expr(sp, true);
-        }
-    };
-
-    let (is_literal, fmt_snippet) = match ecx.source_map().span_to_snippet(fmt_sp) {
-        Ok(s) => (s.starts_with("\"") || s.starts_with("r#"), Some(s)),
-        _ => (false, None),
-    };
-
-    let str_style = match fmt_style {
-        ast::StrStyle::Cooked => None,
-        ast::StrStyle::Raw(raw) => Some(raw as usize),
-    };
-
-    /// Finds the indices of all characters that have been processed and differ between the actual
-    /// written code (code snippet) and the `InternedString` that get's processed in the `Parser`
-    /// in order to properly synthethise the intra-string `Span`s for error diagnostics.
-    fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> {
-        let mut eat_ws = false;
-        let mut s = snippet.chars().enumerate().peekable();
-        let mut skips = vec![];
-        while let Some((pos, c)) = s.next() {
-            match (c, s.peek()) {
-                // skip whitespace and empty lines ending in '\\'
-                ('\\', Some((next_pos, '\n'))) if !is_raw => {
-                    eat_ws = true;
-                    skips.push(pos);
-                    skips.push(*next_pos);
-                    let _ = s.next();
-                }
-                ('\\', Some((next_pos, '\n')))
-                | ('\\', Some((next_pos, 'n')))
-                | ('\\', Some((next_pos, 't')))
-                    if eat_ws =>
-                {
-                    skips.push(pos);
-                    skips.push(*next_pos);
-                    let _ = s.next();
-                }
-                (' ', _) | ('\n', _) | ('\t', _) if eat_ws => {
-                    skips.push(pos);
-                }
-                ('\\', Some((next_pos, 'n')))
-                | ('\\', Some((next_pos, 't')))
-                | ('\\', Some((next_pos, '0')))
-                | ('\\', Some((next_pos, '\\')))
-                | ('\\', Some((next_pos, '\'')))
-                | ('\\', Some((next_pos, '\"'))) => {
-                    skips.push(*next_pos);
-                    let _ = s.next();
-                }
-                ('\\', Some((_, 'x'))) if !is_raw => {
-                    for _ in 0..3 {
-                        // consume `\xAB` literal
-                        if let Some((pos, _)) = s.next() {
-                            skips.push(pos);
-                        } else {
-                            break;
-                        }
-                    }
-                }
-                ('\\', Some((_, 'u'))) if !is_raw => {
-                    if let Some((pos, _)) = s.next() {
-                        skips.push(pos);
-                    }
-                    if let Some((next_pos, next_c)) = s.next() {
-                        if next_c == '{' {
-                            skips.push(next_pos);
-                            let mut i = 0; // consume up to 6 hexanumeric chars + closing `}`
-                            while let (Some((next_pos, c)), true) = (s.next(), i < 7) {
-                                if c.is_digit(16) {
-                                    skips.push(next_pos);
-                                } else if c == '}' {
-                                    skips.push(next_pos);
-                                    break;
-                                } else {
-                                    break;
-                                }
-                                i += 1;
-                            }
-                        } else if next_c.is_digit(16) {
-                            skips.push(next_pos);
-                            // We suggest adding `{` and `}` when appropriate, accept it here as if
-                            // it were correct
-                            let mut i = 0; // consume up to 6 hexanumeric chars
-                            while let (Some((next_pos, c)), _) = (s.next(), i < 6) {
-                                if c.is_digit(16) {
-                                    skips.push(next_pos);
-                                } else {
-                                    break;
-                                }
-                                i += 1;
-                            }
-                        }
-                    }
-                }
-                _ if eat_ws => {
-                    // `take_while(|c| c.is_whitespace())`
-                    eat_ws = false;
-                }
-                _ => {}
-            }
-        }
-        skips
-    }
-
-    let skips = if let (true, Some(ref snippet)) = (is_literal, fmt_snippet.as_ref()) {
-        let r_start = str_style.map(|r| r + 1).unwrap_or(0);
-        let r_end = str_style.map(|r| r).unwrap_or(0);
-        let s = &snippet[r_start + 1..snippet.len() - r_end - 1];
-        find_skips(s, str_style.is_some())
-    } else {
-        vec![]
-    };
-
-    let fmt_str = &fmt_str.as_str(); // for the suggestions below
-    let mut parser = parse::Parser::new(fmt_str, str_style, skips, append_newline);
-
-    let mut unverified_pieces = Vec::new();
-    while let Some(piece) = parser.next() {
-        if !parser.errors.is_empty() {
-            break;
-        } else {
-            unverified_pieces.push(piece);
-        }
-    }
-
-    if !parser.errors.is_empty() {
-        let err = parser.errors.remove(0);
-        let sp = fmt_span.from_inner(err.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 {
-            e.note(&note);
-        }
-        if let Some((label, span)) = err.secondary_label {
-            let sp = fmt_span.from_inner(span);
-            e.span_label(sp, label);
-        }
-        e.emit();
-        return DummyResult::raw_expr(sp, true);
-    }
-
-    let arg_spans = parser.arg_places.iter().map(|span| fmt_span.from_inner(*span)).collect();
-
-    let named_pos: FxHashSet<usize> = names.values().cloned().collect();
-
-    let mut cx = Context {
-        ecx,
-        args,
-        arg_types,
-        arg_unique_types,
-        names,
-        curarg: 0,
-        curpiece: 0,
-        arg_index_map: Vec::new(),
-        count_args: Vec::new(),
-        count_positions: FxHashMap::default(),
-        count_positions_count: 0,
-        count_args_index_offset: 0,
-        literal: String::new(),
-        pieces: Vec::with_capacity(unverified_pieces.len()),
-        str_pieces: Vec::with_capacity(unverified_pieces.len()),
-        all_pieces_simple: true,
-        macsp,
-        fmtsp: fmt_span,
-        invalid_refs: Vec::new(),
-        arg_spans,
-        arg_with_formatting: Vec::new(),
-        is_literal,
-    };
-
-    // This needs to happen *after* the Parser has consumed all pieces to create all the spans
-    let pieces = unverified_pieces
-        .into_iter()
-        .map(|mut piece| {
-            cx.verify_piece(&piece);
-            cx.resolve_name_inplace(&mut piece);
-            piece
-        })
-        .collect::<Vec<_>>();
-
-    let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg {
-        parse::String(_) => false,
-        parse::NextArgument(arg) => match arg.position {
-            parse::Position::ArgumentIs(_) => true,
-            _ => false,
-        },
-    });
-
-    cx.build_index_map();
-
-    let mut arg_index_consumed = vec![0usize; cx.arg_index_map.len()];
-
-    for piece in pieces {
-        if let Some(piece) = cx.build_piece(&piece, &mut arg_index_consumed) {
-            let s = cx.build_literal_string();
-            cx.str_pieces.push(s);
-            cx.pieces.push(piece);
-        }
-    }
-
-    if !cx.literal.is_empty() {
-        let s = cx.build_literal_string();
-        cx.str_pieces.push(s);
-    }
-
-    if cx.invalid_refs.len() >= 1 {
-        cx.report_invalid_references(numbered_position_args);
-    }
-
-    // Make sure that all arguments were used and all arguments have types.
-    let errs = cx
-        .arg_types
-        .iter()
-        .enumerate()
-        .filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i))
-        .map(|(i, _)| {
-            let msg = if named_pos.contains(&i) {
-                // named argument
-                "named argument never used"
-            } else {
-                // positional argument
-                "argument never used"
-            };
-            (cx.args[i].span, msg)
-        })
-        .collect::<Vec<_>>();
-
-    let errs_len = errs.len();
-    if !errs.is_empty() {
-        let args_used = cx.arg_types.len() - errs_len;
-        let args_unused = errs_len;
-
-        let mut diag = {
-            if errs_len == 1 {
-                let (sp, msg) = errs.into_iter().next().unwrap();
-                let mut diag = cx.ecx.struct_span_err(sp, msg);
-                diag.span_label(sp, msg);
-                diag
-            } else {
-                let mut diag = cx.ecx.struct_span_err(
-                    errs.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
-                    "multiple unused formatting arguments",
-                );
-                diag.span_label(cx.fmtsp, "multiple missing formatting specifiers");
-                for (sp, msg) in errs {
-                    diag.span_label(sp, msg);
-                }
-                diag
-            }
-        };
-
-        // Used to ensure we only report translations for *one* kind of foreign format.
-        let mut found_foreign = false;
-        // Decide if we want to look for foreign formatting directives.
-        if args_used < args_unused {
-            use super::format_foreign as foreign;
-
-            // The set of foreign substitutions we've explained.  This prevents spamming the user
-            // with `%d should be written as {}` over and over again.
-            let mut explained = FxHashSet::default();
-
-            macro_rules! check_foreign {
-                ($kind:ident) => {{
-                    let mut show_doc_note = false;
-
-                    let mut suggestions = vec![];
-                    // account for `"` and account for raw strings `r#`
-                    let padding = str_style.map(|i| i + 2).unwrap_or(1);
-                    for sub in foreign::$kind::iter_subs(fmt_str, padding) {
-                        let trn = match sub.translate() {
-                            Some(trn) => trn,
-
-                            // If it has no translation, don't call it out specifically.
-                            None => continue,
-                        };
-
-                        let pos = sub.position();
-                        let sub = String::from(sub.as_str());
-                        if explained.contains(&sub) {
-                            continue;
-                        }
-                        explained.insert(sub.clone());
-
-                        if !found_foreign {
-                            found_foreign = true;
-                            show_doc_note = true;
-                        }
-
-                        if let Some(inner_sp) = pos {
-                            let sp = fmt_sp.from_inner(inner_sp);
-                            suggestions.push((sp, trn));
-                        } else {
-                            diag.help(&format!("`{}` should be written as `{}`", sub, trn));
-                        }
-                    }
-
-                    if show_doc_note {
-                        diag.note(concat!(
-                            stringify!($kind),
-                            " formatting not supported; see the documentation for `std::fmt`",
-                        ));
-                    }
-                    if suggestions.len() > 0 {
-                        diag.multipart_suggestion(
-                            "format specifiers use curly braces",
-                            suggestions,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                }};
-            }
-
-            check_foreign!(printf);
-            if !found_foreign {
-                check_foreign!(shell);
-            }
-        }
-        if !found_foreign && errs_len == 1 {
-            diag.span_label(cx.fmtsp, "formatting specifier missing");
-        }
-
-        diag.emit();
-    }
-
-    cx.into_expr()
-}