about summary refs log tree commit diff
path: root/compiler/rustc_builtin_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs200
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs60
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs192
-rw-r--r--compiler/rustc_builtin_macros/src/concat_idents.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs200
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs221
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs28
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs14
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/llvm_asm.rs303
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs70
-rw-r--r--compiler/rustc_builtin_macros/src/util.rs35
19 files changed, 665 insertions, 712 deletions
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 198287f608e..1a6e5694791 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -8,20 +8,21 @@ use rustc_expand::base::{self, *};
 use rustc_parse::parser::Parser;
 use rustc_parse_format as parse;
 use rustc_session::lint;
+use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{InnerSpan, Span};
 use rustc_target::asm::InlineAsmArch;
 use smallvec::smallvec;
 
-struct AsmArgs {
-    templates: Vec<P<ast::Expr>>,
-    operands: Vec<(ast::InlineAsmOperand, Span)>,
+pub struct AsmArgs {
+    pub templates: Vec<P<ast::Expr>>,
+    pub operands: Vec<(ast::InlineAsmOperand, Span)>,
     named_args: FxHashMap<Symbol, usize>,
     reg_args: FxHashSet<usize>,
-    clobber_abi: Option<(Symbol, Span)>,
+    pub clobber_abis: Vec<(Symbol, Span)>,
     options: ast::InlineAsmOptions,
-    options_spans: Vec<Span>,
+    pub options_spans: Vec<Span>,
 }
 
 fn parse_args<'a>(
@@ -31,31 +32,22 @@ fn parse_args<'a>(
     is_global_asm: bool,
 ) -> Result<AsmArgs, DiagnosticBuilder<'a>> {
     let mut p = ecx.new_parser_from_tts(tts);
+    let sess = &ecx.sess.parse_sess;
+    parse_asm_args(&mut p, sess, sp, is_global_asm)
+}
 
-    if p.token == token::Eof {
-        return Err(ecx.struct_span_err(sp, "requires at least a template string argument"));
-    }
+// Primarily public for rustfmt consumption.
+// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
+pub fn parse_asm_args<'a>(
+    p: &mut Parser<'a>,
+    sess: &'a ParseSess,
+    sp: Span,
+    is_global_asm: bool,
+) -> Result<AsmArgs, DiagnosticBuilder<'a>> {
+    let diag = &sess.span_diagnostic;
 
-    // Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
-    if !is_global_asm && p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) {
-        let mut err =
-            ecx.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
-        err.note("consider migrating to the new asm! syntax specified in RFC 2873");
-        err.note("alternatively, switch to llvm_asm! to keep your code working as it is");
-
-        // Find the span of the "asm!" so that we can offer an automatic suggestion
-        let asm_span = sp.from_inner(InnerSpan::new(0, 4));
-        if let Ok(s) = ecx.source_map().span_to_snippet(asm_span) {
-            if s == "asm!" {
-                err.span_suggestion(
-                    asm_span,
-                    "replace with",
-                    "llvm_asm!".into(),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-        return Err(err);
+    if p.token == token::Eof {
+        return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
     }
 
     let first_template = p.parse_expr()?;
@@ -64,7 +56,7 @@ fn parse_args<'a>(
         operands: vec![],
         named_args: FxHashMap::default(),
         reg_args: FxHashSet::default(),
-        clobber_abi: None,
+        clobber_abis: Vec::new(),
         options: ast::InlineAsmOptions::empty(),
         options_spans: vec![],
     };
@@ -74,7 +66,7 @@ fn parse_args<'a>(
         if !p.eat(&token::Comma) {
             if allow_templates {
                 // After a template string, we always expect *only* a comma...
-                let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+                let mut err = diag.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);
@@ -89,14 +81,14 @@ fn parse_args<'a>(
 
         // Parse clobber_abi
         if p.eat_keyword(sym::clobber_abi) {
-            parse_clobber_abi(&mut p, &mut args)?;
+            parse_clobber_abi(p, &mut args)?;
             allow_templates = false;
             continue;
         }
 
         // Parse options
         if p.eat_keyword(sym::options) {
-            parse_options(&mut p, &mut args, is_global_asm)?;
+            parse_options(p, &mut args, is_global_asm)?;
             allow_templates = false;
             continue;
         }
@@ -116,25 +108,25 @@ fn parse_args<'a>(
 
         let mut explicit_reg = false;
         let op = if !is_global_asm && p.eat_keyword(kw::In) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
                 return Err(err);
             }
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
         } else if !is_global_asm && p.eat_keyword(sym::out) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
         } else if !is_global_asm && p.eat_keyword(sym::lateout) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
         } else if !is_global_asm && p.eat_keyword(sym::inout) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
                 return Err(err);
             }
             let expr = p.parse_expr()?;
@@ -146,9 +138,9 @@ fn parse_args<'a>(
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
         } else if !is_global_asm && p.eat_keyword(sym::inlateout) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
                 return Err(err);
             }
             let expr = p.parse_expr()?;
@@ -167,7 +159,7 @@ fn parse_args<'a>(
             match expr.kind {
                 ast::ExprKind::Path(..) => {}
                 _ => {
-                    let err = ecx
+                    let err = diag
                         .struct_span_err(expr.span, "argument to `sym` must be a path expression");
                     return Err(err);
                 }
@@ -186,7 +178,7 @@ fn parse_args<'a>(
                     } else {
                         "expected operand, clobber_abi, options, or additional template string"
                     };
-                    let mut err = ecx.struct_span_err(template.span, errstr);
+                    let mut err = diag.struct_span_err(template.span, errstr);
                     err.span_label(template.span, errstr);
                     return Err(err);
                 }
@@ -206,31 +198,31 @@ fn parse_args<'a>(
         // clobber_abi/options. We do this at the end once we have the full span
         // of the argument available.
         if !args.options_spans.is_empty() {
-            ecx.struct_span_err(span, "arguments are not allowed after options")
+            diag.struct_span_err(span, "arguments are not allowed after options")
                 .span_labels(args.options_spans.clone(), "previous options")
                 .span_label(span, "argument")
                 .emit();
-        } else if let Some((_, abi_span)) = args.clobber_abi {
-            ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
-                .span_label(abi_span, "clobber_abi")
+        } else if let Some((_, abi_span)) = args.clobber_abis.last() {
+            diag.struct_span_err(span, "arguments are not allowed after clobber_abi")
+                .span_label(*abi_span, "clobber_abi")
                 .span_label(span, "argument")
                 .emit();
         }
         if explicit_reg {
             if name.is_some() {
-                ecx.struct_span_err(span, "explicit register arguments cannot have names").emit();
+                diag.struct_span_err(span, "explicit register arguments cannot have names").emit();
             }
             args.reg_args.insert(slot);
         } else if let Some(name) = name {
             if let Some(&prev) = args.named_args.get(&name) {
-                ecx.struct_span_err(span, &format!("duplicate argument named `{}`", name))
+                diag.struct_span_err(span, &format!("duplicate argument named `{}`", name))
                     .span_label(args.operands[prev].1, "previously here")
                     .span_label(span, "duplicate argument")
                     .emit();
                 continue;
             }
             if !args.reg_args.is_empty() {
-                let mut err = ecx.struct_span_err(
+                let mut err = diag.struct_span_err(
                     span,
                     "named arguments cannot follow explicit register arguments",
                 );
@@ -243,7 +235,7 @@ fn parse_args<'a>(
             args.named_args.insert(name, slot);
         } else {
             if !args.named_args.is_empty() || !args.reg_args.is_empty() {
-                let mut err = ecx.struct_span_err(
+                let mut err = diag.struct_span_err(
                     span,
                     "positional arguments cannot follow named arguments \
                      or explicit register arguments",
@@ -264,21 +256,21 @@ fn parse_args<'a>(
         && args.options.contains(ast::InlineAsmOptions::READONLY)
     {
         let spans = args.options_spans.clone();
-        ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
+        diag.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
             .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && args.options.contains(ast::InlineAsmOptions::NORETURN)
     {
         let spans = args.options_spans.clone();
-        ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
+        diag.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
             .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
     {
         let spans = args.options_spans.clone();
-        ecx.struct_span_err(
+        diag.struct_span_err(
             spans,
             "the `pure` option must be combined with either `nomem` or `readonly`",
         )
@@ -309,33 +301,39 @@ fn parse_args<'a>(
         }
     }
     if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
-        ecx.struct_span_err(
+        diag.struct_span_err(
             args.options_spans.clone(),
             "asm with the `pure` option must have at least one output",
         )
         .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
-        let err = ecx
+        let err = diag
             .struct_span_err(outputs_sp, "asm outputs are not allowed with the `noreturn` option");
 
         // Bail out now since this is likely to confuse MIR
         return Err(err);
     }
-    if let Some((_, abi_span)) = args.clobber_abi {
+
+    if args.clobber_abis.len() > 0 {
         if is_global_asm {
-            let err =
-                ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`");
+            let err = diag.struct_span_err(
+                args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
+                "`clobber_abi` cannot be used with `global_asm!`",
+            );
 
             // Bail out now since this is likely to confuse later stages
             return Err(err);
         }
         if !regclass_outputs.is_empty() {
-            ecx.struct_span_err(
+            diag.struct_span_err(
                 regclass_outputs.clone(),
                 "asm with `clobber_abi` must specify explicit registers for outputs",
             )
-            .span_label(abi_span, "clobber_abi")
+            .span_labels(
+                args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
+                "clobber_abi",
+            )
             .span_labels(regclass_outputs, "generic outputs")
             .emit();
         }
@@ -414,6 +412,8 @@ fn parse_options<'a>(
             try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
         } else if p.eat_keyword(kw::Raw) {
             try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
+        } else if p.eat_keyword(sym::may_unwind) {
+            try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
         } else {
             return p.unexpected();
         }
@@ -439,37 +439,61 @@ fn parse_clobber_abi<'a>(
 
     p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
 
-    let clobber_abi = match p.parse_str_lit() {
-        Ok(str_lit) => str_lit.symbol_unescaped,
-        Err(opt_lit) => {
-            let span = opt_lit.map_or(p.token.span, |lit| lit.span);
-            let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
-            err.span_label(span, "not a string literal");
-            return Err(err);
-        }
-    };
+    if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+        let err = p.sess.span_diagnostic.struct_span_err(
+            p.token.span,
+            "at least one abi must be provided as an argument to `clobber_abi`",
+        );
+        return Err(err);
+    }
 
-    p.expect(&token::CloseDelim(token::DelimToken::Paren))?;
+    let mut new_abis = Vec::new();
+    loop {
+        match p.parse_str_lit() {
+            Ok(str_lit) => {
+                new_abis.push((str_lit.symbol_unescaped, str_lit.span));
+            }
+            Err(opt_lit) => {
+                // If the non-string literal is a closing paren then it's the end of the list and is fine
+                if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+                    break;
+                }
+                let span = opt_lit.map_or(p.token.span, |lit| lit.span);
+                let mut err =
+                    p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
+                err.span_label(span, "not a string literal");
+                return Err(err);
+            }
+        };
 
-    let new_span = span_start.to(p.prev_token.span);
+        // Allow trailing commas
+        if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+            break;
+        }
+        p.expect(&token::Comma)?;
+    }
 
-    if let Some((_, prev_span)) = args.clobber_abi {
-        let mut err = p
-            .sess
-            .span_diagnostic
-            .struct_span_err(new_span, "clobber_abi specified multiple times");
-        err.span_label(prev_span, "clobber_abi previously specified here");
-        return Err(err);
-    } else if !args.options_spans.is_empty() {
+    let full_span = span_start.to(p.prev_token.span);
+
+    if !args.options_spans.is_empty() {
         let mut err = p
             .sess
             .span_diagnostic
-            .struct_span_err(new_span, "clobber_abi is not allowed after options");
+            .struct_span_err(full_span, "clobber_abi is not allowed after options");
         err.span_labels(args.options_spans.clone(), "options");
         return Err(err);
     }
 
-    args.clobber_abi = Some((clobber_abi, new_span));
+    match &new_abis[..] {
+        // should have errored above during parsing
+        [] => unreachable!(),
+        [(abi, _span)] => args.clobber_abis.push((*abi, full_span)),
+        [abis @ ..] => {
+            for (abi, span) in abis {
+                args.clobber_abis.push((*abi, *span));
+            }
+        }
+    }
 
     Ok(())
 }
@@ -540,14 +564,14 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
             template_snippet.as_ref().map(|s| Symbol::intern(s)),
             template_sp,
         ));
-        let template_str = &template_str.as_str();
+        let template_str = template_str.as_str();
 
         if let Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) = ecx.sess.asm_arch {
             let find_span = |needle: &str| -> Span {
                 if let Some(snippet) = &template_snippet {
                     if let Some(pos) = snippet.find(needle) {
                         let end = pos
-                            + &snippet[pos..]
+                            + snippet[pos..]
                                 .find(|c| matches!(c, '\n' | ';' | '\\' | '"'))
                                 .unwrap_or(snippet[pos..].len() - 1);
                         let inner = InnerSpan::new(pos, end);
@@ -680,7 +704,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                             Some(&idx) => Some(idx),
                             None => {
                                 let msg = format!("there is no argument named `{}`", name);
-                                ecx.struct_span_err(span, &msg[..]).emit();
+                                ecx.struct_span_err(span, &msg).emit();
                                 None
                             }
                         },
@@ -770,13 +794,13 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
         template,
         template_strs: template_strs.into_boxed_slice(),
         operands: args.operands,
-        clobber_abi: args.clobber_abi,
+        clobber_abis: args.clobber_abis,
         options: args.options,
         line_spans,
     })
 }
 
-pub fn expand_asm<'cx>(
+pub(super) fn expand_asm<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
@@ -803,7 +827,7 @@ pub fn expand_asm<'cx>(
     }
 }
 
-pub fn expand_global_asm<'cx>(
+pub(super) fn expand_global_asm<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
@@ -815,7 +839,7 @@ pub fn expand_global_asm<'cx>(
                     ident: Ident::empty(),
                     attrs: Vec::new(),
                     id: ast::DUMMY_NODE_ID,
-                    kind: ast::ItemKind::GlobalAsm(inline_asm),
+                    kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
                     vis: ast::Visibility {
                         span: sp.shrink_to_lo(),
                         kind: ast::VisibilityKind::Inherited,
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 307730f7f5f..31086a2acf8 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -1,4 +1,4 @@
-use crate::util::check_builtin_macro_attribute;
+use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
 
 use rustc_ast as ast;
 use rustc_ast::mut_visit::MutVisitor;
@@ -11,7 +11,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_expand::config::StripUnconfigured;
 use rustc_expand::configure;
 use rustc_feature::Features;
-use rustc_parse::parser::ForceCollect;
+use rustc_parse::parser::{ForceCollect, Parser};
 use rustc_session::utils::FlattenNonterminals;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
@@ -25,6 +25,7 @@ crate fn expand(
     annotatable: Annotatable,
 ) -> Vec<Annotatable> {
     check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
+    warn_on_duplicate_attribute(&ecx, &annotatable, sym::cfg_eval);
     vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
 }
 
@@ -77,6 +78,10 @@ fn flat_map_annotatable(
         Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
         Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
         Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
+        Annotatable::Crate(mut krate) => {
+            vis.visit_crate(&mut krate);
+            Some(Annotatable::Crate(krate))
+        }
     }
 }
 
@@ -101,6 +106,7 @@ impl CfgFinder {
             Annotatable::Param(param) => finder.visit_param(&param),
             Annotatable::FieldDef(field) => finder.visit_field_def(&field),
             Annotatable::Variant(variant) => finder.visit_variant(&variant),
+            Annotatable::Crate(krate) => finder.visit_crate(krate),
         };
         finder.has_cfg_or_cfg_attr
     }
@@ -138,8 +144,34 @@ impl CfgEval<'_, '_> {
         // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
         // process is lossless, so this process is invisible to proc-macros.
 
-        // FIXME - get rid of this clone
-        let nt = annotatable.clone().into_nonterminal();
+        let parse_annotatable_with: fn(&mut Parser<'_>) -> _ = match annotatable {
+            Annotatable::Item(_) => {
+                |parser| Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
+            }
+            Annotatable::TraitItem(_) => |parser| {
+                Annotatable::TraitItem(
+                    parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+                )
+            },
+            Annotatable::ImplItem(_) => |parser| {
+                Annotatable::ImplItem(
+                    parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+                )
+            },
+            Annotatable::ForeignItem(_) => |parser| {
+                Annotatable::ForeignItem(
+                    parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+                )
+            },
+            Annotatable::Stmt(_) => |parser| {
+                Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
+            },
+            Annotatable::Expr(_) => {
+                |parser| Annotatable::Expr(parser.parse_expr_force_collect().unwrap())
+            }
+            _ => unreachable!(),
+        };
+        let nt = annotatable.into_nonterminal();
 
         let mut orig_tokens = rustc_parse::nt_to_tokenstream(
             &nt,
@@ -173,25 +205,7 @@ impl CfgEval<'_, '_> {
         let mut parser =
             rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
         parser.capture_cfg = true;
-        annotatable = match annotatable {
-            Annotatable::Item(_) => {
-                Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
-            }
-            Annotatable::TraitItem(_) => Annotatable::TraitItem(
-                parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
-            ),
-            Annotatable::ImplItem(_) => Annotatable::ImplItem(
-                parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
-            ),
-            Annotatable::ForeignItem(_) => Annotatable::ForeignItem(
-                parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
-            ),
-            Annotatable::Stmt(_) => {
-                Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
-            }
-            Annotatable::Expr(_) => Annotatable::Expr(parser.parse_expr_force_collect().unwrap()),
-            _ => unreachable!(),
-        };
+        annotatable = parse_annotatable_with(&mut parser);
 
         // Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
         // our attribute target will correctly the tokens as well.
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index e5077d93674..59361510a67 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -21,7 +21,7 @@ pub fn expand_concat(
         match e.kind {
             ast::ExprKind::Lit(ref lit) => match lit.kind {
                 ast::LitKind::Str(ref s, _) | ast::LitKind::Float(ref s, _) => {
-                    accumulator.push_str(&s.as_str());
+                    accumulator.push_str(s.as_str());
                 }
                 ast::LitKind::Char(c) => {
                     accumulator.push(c);
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
new file mode 100644
index 00000000000..eb08170959b
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -0,0 +1,192 @@
+use rustc_ast as ast;
+use rustc_ast::{ptr::P, tokenstream::TokenStream};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::Applicability;
+use rustc_expand::base::{self, DummyResult};
+
+/// Emits errors for literal expressions that are invalid inside and outside of an array.
+fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_nested: bool) {
+    let lit = if let ast::ExprKind::Lit(lit) = &expr.kind {
+        lit
+    } else {
+        unreachable!();
+    };
+    match lit.kind {
+        ast::LitKind::Char(_) => {
+            let mut err = cx.struct_span_err(expr.span, "cannot concatenate character literals");
+            if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
+                err.span_suggestion(
+                    expr.span,
+                    "try using a byte character",
+                    format!("b{}", snippet),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+            }
+        }
+        ast::LitKind::Str(_, _) => {
+            let mut err = cx.struct_span_err(expr.span, "cannot concatenate string literals");
+            // suggestion would be invalid if we are nested
+            if !is_nested {
+                if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
+                    err.span_suggestion(
+                        expr.span,
+                        "try using a byte string",
+                        format!("b{}", snippet),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+            err.emit();
+        }
+        ast::LitKind::Float(_, _) => {
+            cx.span_err(expr.span, "cannot concatenate float literals");
+        }
+        ast::LitKind::Bool(_) => {
+            cx.span_err(expr.span, "cannot concatenate boolean literals");
+        }
+        ast::LitKind::Err(_) => {}
+        ast::LitKind::Int(_, _) if !is_nested => {
+            let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals");
+            if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
+                err.span_suggestion(
+                    expr.span,
+                    "try wrapping the number in an array",
+                    format!("[{}]", snippet),
+                    Applicability::MachineApplicable,
+                );
+            }
+            err.emit();
+        }
+        ast::LitKind::Int(
+            val,
+            ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
+        ) => {
+            assert!(val > u8::MAX.into()); // must be an error
+            cx.span_err(expr.span, "numeric literal is out of bounds");
+        }
+        ast::LitKind::Int(_, _) => {
+            cx.span_err(expr.span, "numeric literal is not a `u8`");
+        }
+        _ => unreachable!(),
+    }
+}
+
+fn handle_array_element(
+    cx: &mut base::ExtCtxt<'_>,
+    has_errors: &mut bool,
+    missing_literals: &mut Vec<rustc_span::Span>,
+    expr: &P<rustc_ast::Expr>,
+) -> Option<u8> {
+    match expr.kind {
+        ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
+            if !*has_errors {
+                cx.span_err(expr.span, "cannot concatenate doubly nested array");
+            }
+            *has_errors = true;
+            None
+        }
+        ast::ExprKind::Lit(ref lit) => match lit.kind {
+            ast::LitKind::Int(
+                val,
+                ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
+            ) if val <= u8::MAX.into() => Some(val as u8),
+
+            ast::LitKind::Byte(val) => Some(val),
+            ast::LitKind::ByteStr(_) => {
+                if !*has_errors {
+                    cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
+                        .note("byte strings are treated as arrays of bytes")
+                        .help("try flattening the array")
+                        .emit();
+                }
+                *has_errors = true;
+                None
+            }
+            _ => {
+                if !*has_errors {
+                    invalid_type_err(cx, expr, true);
+                }
+                *has_errors = true;
+                None
+            }
+        },
+        _ => {
+            missing_literals.push(expr.span);
+            None
+        }
+    }
+}
+
+pub fn expand_concat_bytes(
+    cx: &mut base::ExtCtxt<'_>,
+    sp: rustc_span::Span,
+    tts: TokenStream,
+) -> Box<dyn base::MacResult + 'static> {
+    let es = match base::get_exprs_from_tts(cx, sp, tts) {
+        Some(e) => e,
+        None => return DummyResult::any(sp),
+    };
+    let mut accumulator = Vec::new();
+    let mut missing_literals = vec![];
+    let mut has_errors = false;
+    for e in es {
+        match e.kind {
+            ast::ExprKind::Array(ref exprs) => {
+                for expr in exprs {
+                    if let Some(elem) =
+                        handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
+                    {
+                        accumulator.push(elem);
+                    }
+                }
+            }
+            ast::ExprKind::Repeat(ref expr, ref count) => {
+                if let ast::ExprKind::Lit(ast::Lit {
+                    kind: ast::LitKind::Int(count_val, _), ..
+                }) = count.value.kind
+                {
+                    if let Some(elem) =
+                        handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
+                    {
+                        for _ in 0..count_val {
+                            accumulator.push(elem);
+                        }
+                    }
+                } else {
+                    cx.span_err(count.value.span, "repeat count is not a positive number");
+                }
+            }
+            ast::ExprKind::Lit(ref lit) => match lit.kind {
+                ast::LitKind::Byte(val) => {
+                    accumulator.push(val);
+                }
+                ast::LitKind::ByteStr(ref bytes) => {
+                    accumulator.extend_from_slice(&bytes);
+                }
+                _ => {
+                    if !has_errors {
+                        invalid_type_err(cx, &e, false);
+                    }
+                    has_errors = true;
+                }
+            },
+            ast::ExprKind::Err => {
+                has_errors = true;
+            }
+            _ => {
+                missing_literals.push(e.span);
+            }
+        }
+    }
+    if !missing_literals.is_empty() {
+        let mut err = cx.struct_span_err(missing_literals.clone(), "expected a byte literal");
+        err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`");
+        err.emit();
+        return base::MacEager::expr(DummyResult::raw_expr(sp, true));
+    } else if has_errors {
+        return base::MacEager::expr(DummyResult::raw_expr(sp, true));
+    }
+    let sp = cx.with_def_site_ctxt(sp);
+    base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::from(accumulator))))
+}
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index 53a456b69ac..239bafb266a 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -29,7 +29,7 @@ pub fn expand_concat_idents<'cx>(
         } else {
             if let TokenTree::Token(token) = e {
                 if let Some((ident, _)) = token.ident() {
-                    res_str.push_str(&ident.name.as_str());
+                    res_str.push_str(ident.name.as_str());
                     continue;
                 }
             }
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index 31a35b9b7b4..47d7b6c259e 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -121,7 +121,7 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
 
 fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) {
     let help_msg = match lit.token.kind {
-        token::Str if rustc_lexer::is_ident(&lit.token.symbol.as_str()) => {
+        token::Str if rustc_lexer::is_ident(lit.token.symbol.as_str()) => {
             format!("try using `#[derive({})]`", lit.token.symbol)
         }
         _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index a225b328ab6..985c45e2253 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -557,18 +557,21 @@ impl<'a> TraitDef<'a> {
                     tokens: None,
                 },
                 attrs: Vec::new(),
-                kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAliasKind(
-                    ast::Defaultness::Final,
-                    Generics::default(),
-                    Vec::new(),
-                    Some(type_def.to_ty(cx, self.span, type_ident, generics)),
-                ))),
+                kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
+                    defaultness: ast::Defaultness::Final,
+                    generics: Generics::default(),
+                    bounds: Vec::new(),
+                    ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
+                })),
                 tokens: None,
             })
         });
 
-        let Generics { mut params, mut where_clause, span } =
+        let Generics { mut params, mut where_clause, .. } =
             self.generics.to_generics(cx, self.span, type_ident, generics);
+        where_clause.span = generics.where_clause.span;
+        let ctxt = self.span.ctxt();
+        let span = generics.span.with_ctxt(ctxt);
 
         // Create the generic parameters
         params.extend(generics.params.iter().map(|param| match &param.kind {
@@ -589,12 +592,12 @@ impl<'a> TraitDef<'a> {
                         param.bounds.iter().cloned()
                     ).collect();
 
-                cx.typaram(self.span, param.ident, vec![], bounds, None)
+                cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None)
             }
             GenericParamKind::Const { ty, kw_span, .. } => {
                 let const_nodefault_kind = GenericParamKind::Const {
                     ty: ty.clone(),
-                    kw_span: *kw_span,
+                    kw_span: kw_span.with_ctxt(ctxt),
 
                     // We can't have default values inside impl block
                     default: None,
@@ -607,28 +610,27 @@ impl<'a> TraitDef<'a> {
 
         // and similarly for where clauses
         where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
-            match *clause {
-                ast::WherePredicate::BoundPredicate(ref wb) => {
+            match clause {
+                ast::WherePredicate::BoundPredicate(wb) => {
+                    let span = wb.span.with_ctxt(ctxt);
                     ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
-                        span: self.span,
-                        bound_generic_params: wb.bound_generic_params.clone(),
-                        bounded_ty: wb.bounded_ty.clone(),
-                        bounds: wb.bounds.to_vec(),
+                        span,
+                        ..wb.clone()
                     })
                 }
-                ast::WherePredicate::RegionPredicate(ref rb) => {
+                ast::WherePredicate::RegionPredicate(wr) => {
+                    let span = wr.span.with_ctxt(ctxt);
                     ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
-                        span: self.span,
-                        lifetime: rb.lifetime,
-                        bounds: rb.bounds.to_vec(),
+                        span,
+                        ..wr.clone()
                     })
                 }
-                ast::WherePredicate::EqPredicate(ref we) => {
+                ast::WherePredicate::EqPredicate(we) => {
+                    let span = we.span.with_ctxt(ctxt);
                     ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
                         id: ast::DUMMY_NODE_ID,
-                        span: self.span,
-                        lhs_ty: we.lhs_ty.clone(),
-                        rhs_ty: we.rhs_ty.clone(),
+                        span,
+                        ..we.clone()
                     })
                 }
             }
@@ -691,13 +693,13 @@ impl<'a> TraitDef<'a> {
             .iter()
             .map(|param| match param.kind {
                 GenericParamKind::Lifetime { .. } => {
-                    GenericArg::Lifetime(cx.lifetime(self.span, param.ident))
+                    GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
                 }
                 GenericParamKind::Type { .. } => {
-                    GenericArg::Type(cx.ty_ident(self.span, param.ident))
+                    GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
                 }
                 GenericParamKind::Const { .. } => {
-                    GenericArg::Const(cx.const_ident(self.span, param.ident))
+                    GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
                 }
             })
             .collect();
@@ -726,7 +728,7 @@ impl<'a> TraitDef<'a> {
             self.span,
             Ident::empty(),
             a,
-            ast::ItemKind::Impl(Box::new(ast::ImplKind {
+            ast::ItemKind::Impl(Box::new(ast::Impl {
                 unsafety,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
@@ -764,8 +766,8 @@ impl<'a> TraitDef<'a> {
                         self,
                         struct_def,
                         type_ident,
-                        &self_args[..],
-                        &nonself_args[..],
+                        &self_args,
+                        &nonself_args,
                     )
                 } else {
                     method_def.expand_struct_method_body(
@@ -773,8 +775,8 @@ impl<'a> TraitDef<'a> {
                         self,
                         struct_def,
                         type_ident,
-                        &self_args[..],
-                        &nonself_args[..],
+                        &self_args,
+                        &nonself_args,
                         use_temporaries,
                     )
                 };
@@ -813,8 +815,8 @@ impl<'a> TraitDef<'a> {
                         self,
                         enum_def,
                         type_ident,
-                        &self_args[..],
-                        &nonself_args[..],
+                        &self_args,
+                        &nonself_args,
                     )
                 } else {
                     method_def.expand_enum_method_body(
@@ -823,7 +825,7 @@ impl<'a> TraitDef<'a> {
                         enum_def,
                         type_ident,
                         self_args,
-                        &nonself_args[..],
+                        &nonself_args,
                     )
                 };
 
@@ -845,16 +847,17 @@ impl<'a> MethodDef<'a> {
         nonself_args: &[P<Expr>],
         fields: &SubstructureFields<'_>,
     ) -> P<Expr> {
+        let span = trait_.span;
         let substructure = Substructure {
             type_ident,
-            method_ident: Ident::new(self.name, trait_.span),
+            method_ident: Ident::new(self.name, span),
             self_args,
             nonself_args,
             fields,
         };
         let mut f = self.combine_substructure.borrow_mut();
         let f: &mut CombineSubstructureFunc<'_> = &mut *f;
-        f(cx, trait_.span, &substructure)
+        f(cx, span, &substructure)
     }
 
     fn get_ret_ty(
@@ -882,9 +885,10 @@ impl<'a> MethodDef<'a> {
         let mut nonself_args = Vec::new();
         let mut arg_tys = Vec::new();
         let mut nonstatic = false;
+        let span = trait_.span;
 
         let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
-            let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr);
+            let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
 
             self_args.push(self_expr);
             nonstatic = true;
@@ -893,11 +897,11 @@ impl<'a> MethodDef<'a> {
         });
 
         for (ty, name) in self.args.iter() {
-            let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
-            let ident = Ident::new(*name, trait_.span);
+            let ast_ty = ty.to_ty(cx, span, type_ident, generics);
+            let ident = Ident::new(*name, span);
             arg_tys.push((ident, ast_ty));
 
-            let arg_expr = cx.expr_ident(trait_.span, ident);
+            let arg_expr = cx.expr_ident(span, ident);
 
             match *ty {
                 // for static methods, just treat any Self
@@ -906,7 +910,7 @@ impl<'a> MethodDef<'a> {
                     self_args.push(arg_expr);
                 }
                 Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
-                    self_args.push(cx.expr_deref(trait_.span, arg_expr))
+                    self_args.push(cx.expr_deref(span, arg_expr))
                 }
                 _ => {
                     nonself_args.push(arg_expr);
@@ -927,53 +931,53 @@ impl<'a> MethodDef<'a> {
         arg_types: Vec<(Ident, P<ast::Ty>)>,
         body: P<Expr>,
     ) -> P<ast::AssocItem> {
+        let span = trait_.span;
         // Create the generics that aren't for `Self`.
-        let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
+        let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
 
         let args = {
             let self_args = explicit_self.map(|explicit_self| {
-                let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span);
+                let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
                 ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
             });
-            let nonself_args =
-                arg_types.into_iter().map(|(name, ty)| cx.param(trait_.span, name, ty));
+            let nonself_args = arg_types.into_iter().map(|(name, ty)| cx.param(span, name, ty));
             self_args.into_iter().chain(nonself_args).collect()
         };
 
         let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
 
-        let method_ident = Ident::new(self.name, trait_.span);
+        let method_ident = Ident::new(self.name, span);
         let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
         let body_block = cx.block_expr(body);
 
-        let unsafety = if self.is_unsafe { ast::Unsafe::Yes(trait_.span) } else { ast::Unsafe::No };
+        let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
 
-        let trait_lo_sp = trait_.span.shrink_to_lo();
+        let trait_lo_sp = span.shrink_to_lo();
 
         let sig = ast::FnSig {
             header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
             decl: fn_decl,
-            span: trait_.span,
+            span,
         };
-        let def = ast::Defaultness::Final;
+        let defaultness = ast::Defaultness::Final;
 
         // Create the method.
         P(ast::AssocItem {
             id: ast::DUMMY_NODE_ID,
             attrs: self.attributes.clone(),
-            span: trait_.span,
+            span,
             vis: ast::Visibility {
                 span: trait_lo_sp,
                 kind: ast::VisibilityKind::Inherited,
                 tokens: None,
             },
             ident: method_ident,
-            kind: ast::AssocItemKind::Fn(Box::new(ast::FnKind(
-                def,
+            kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
+                defaultness,
                 sig,
-                fn_generics,
-                Some(body_block),
-            ))),
+                generics: fn_generics,
+                body: Some(body_block),
+            })),
             tokens: None,
         })
     }
@@ -1024,11 +1028,11 @@ impl<'a> MethodDef<'a> {
         nonself_args: &[P<Expr>],
         use_temporaries: bool,
     ) -> P<Expr> {
-        let mut raw_fields = Vec::new(); // Vec<[fields of self],
-        // [fields of next Self arg], [etc]>
+        let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
+        let span = trait_.span;
         let mut patterns = Vec::new();
         for i in 0..self_args.len() {
-            let struct_path = cx.path(trait_.span, vec![type_ident]);
+            let struct_path = cx.path(span, vec![type_ident]);
             let (pat, ident_expr) = trait_.create_struct_pattern(
                 cx,
                 struct_path,
@@ -1048,7 +1052,7 @@ impl<'a> MethodDef<'a> {
             let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect();
             first_field
                 .map(|(span, opt_id, field, attrs)| FieldInfo {
-                    span,
+                    span: span.with_ctxt(trait_.span.ctxt()),
                     name: opt_id,
                     self_: field,
                     other: other_fields
@@ -1062,7 +1066,7 @@ impl<'a> MethodDef<'a> {
                 })
                 .collect()
         } else {
-            cx.span_bug(trait_.span, "no `self` parameter for method in generic `derive`")
+            cx.span_bug(span, "no `self` parameter for method in generic `derive`")
         };
 
         // body of the inner most destructuring match
@@ -1079,11 +1083,7 @@ impl<'a> MethodDef<'a> {
         // structs. This is actually right-to-left, but it shouldn't
         // matter.
         for (arg_expr, pat) in iter::zip(self_args, patterns) {
-            body = cx.expr_match(
-                trait_.span,
-                arg_expr.clone(),
-                vec![cx.arm(trait_.span, pat.clone(), body)],
-            )
+            body = cx.expr_match(span, arg_expr.clone(), vec![cx.arm(span, pat.clone(), body)])
         }
 
         body
@@ -1193,7 +1193,7 @@ impl<'a> MethodDef<'a> {
         mut self_args: Vec<P<Expr>>,
         nonself_args: &[P<Expr>],
     ) -> P<Expr> {
-        let sp = trait_.span;
+        let span = trait_.span;
         let variants = &enum_def.variants;
 
         let self_arg_names = iter::once("__self".to_string())
@@ -1208,7 +1208,7 @@ impl<'a> MethodDef<'a> {
 
         let self_arg_idents = self_arg_names
             .iter()
-            .map(|name| Ident::from_str_and_span(name, sp))
+            .map(|name| Ident::from_str_and_span(name, span))
             .collect::<Vec<Ident>>();
 
         // The `vi_idents` will be bound, solely in the catch-all, to
@@ -1217,8 +1217,8 @@ impl<'a> MethodDef<'a> {
         let vi_idents = self_arg_names
             .iter()
             .map(|name| {
-                let vi_suffix = format!("{}_vi", &name[..]);
-                Ident::from_str_and_span(&vi_suffix, trait_.span)
+                let vi_suffix = format!("{}_vi", name);
+                Ident::from_str_and_span(&vi_suffix, span)
             })
             .collect::<Vec<Ident>>();
 
@@ -1226,7 +1226,7 @@ impl<'a> MethodDef<'a> {
         // delegated expression that handles the catch-all case,
         // using `__variants_tuple` to drive logic if necessary.
         let catch_all_substructure =
-            EnumNonMatchingCollapsed(self_arg_idents, &variants[..], &vi_idents[..]);
+            EnumNonMatchingCollapsed(self_arg_idents, &variants, &vi_idents);
 
         let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
 
@@ -1248,7 +1248,7 @@ impl<'a> MethodDef<'a> {
                         self_arg_name,
                         ast::Mutability::Not,
                     );
-                    (cx.pat(sp, PatKind::Ref(p, ast::Mutability::Not)), idents)
+                    (cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)), idents)
                 };
 
                 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
@@ -1261,13 +1261,13 @@ impl<'a> MethodDef<'a> {
                     idents
                 };
                 for self_arg_name in &self_arg_names[1..] {
-                    let (p, idents) = mk_self_pat(cx, &self_arg_name[..]);
+                    let (p, idents) = mk_self_pat(cx, &self_arg_name);
                     subpats.push(p);
                     self_pats_idents.push(idents);
                 }
 
                 // Here is the pat = `(&VariantK, &VariantK, ...)`
-                let single_pat = cx.pat_tuple(sp, subpats);
+                let single_pat = cx.pat_tuple(span, subpats);
 
                 // For the BodyK, we need to delegate to our caller,
                 // passing it an EnumMatching to indicate which case
@@ -1284,7 +1284,7 @@ impl<'a> MethodDef<'a> {
                     .into_iter()
                     .enumerate()
                     // For each arg field of self, pull out its getter expr ...
-                    .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| {
+                    .map(|(field_index, (span, opt_ident, self_getter_expr, attrs))| {
                         // ... but FieldInfo also wants getter expr
                         // for matching other arguments of Self type;
                         // so walk across the *other* self_pats_idents
@@ -1307,7 +1307,7 @@ impl<'a> MethodDef<'a> {
                             .collect::<Vec<P<Expr>>>();
 
                         FieldInfo {
-                            span: sp,
+                            span,
                             name: opt_ident,
                             self_: self_getter_expr,
                             other: others,
@@ -1330,7 +1330,7 @@ impl<'a> MethodDef<'a> {
                     &substructure,
                 );
 
-                cx.arm(sp, single_pat, arm_expr)
+                cx.arm(span, single_pat, arm_expr)
             })
             .collect();
 
@@ -1353,12 +1353,12 @@ impl<'a> MethodDef<'a> {
                 // Since we know that all the arguments will match if we reach
                 // the match expression we add the unreachable intrinsics as the
                 // result of the catch all which should help llvm in optimizing it
-                Some(deriving::call_unreachable(cx, sp))
+                Some(deriving::call_unreachable(cx, span))
             }
             _ => None,
         };
         if let Some(arm) = default {
-            match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm));
+            match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
         }
 
         // We will usually need the catch-all after matching the
@@ -1392,23 +1392,23 @@ impl<'a> MethodDef<'a> {
 
             // We also build an expression which checks whether all discriminants are equal
             // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
-            let mut discriminant_test = cx.expr_bool(sp, true);
+            let mut discriminant_test = cx.expr_bool(span, true);
 
             let mut first_ident = None;
             for (&ident, self_arg) in iter::zip(&vi_idents, &self_args) {
-                let self_addr = cx.expr_addr_of(sp, self_arg.clone());
+                let self_addr = cx.expr_addr_of(span, self_arg.clone());
                 let variant_value =
-                    deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]);
-                let let_stmt = cx.stmt_let(sp, false, ident, variant_value);
+                    deriving::call_intrinsic(cx, span, sym::discriminant_value, vec![self_addr]);
+                let let_stmt = cx.stmt_let(span, false, ident, variant_value);
                 index_let_stmts.push(let_stmt);
 
                 match first_ident {
                     Some(first) => {
-                        let first_expr = cx.expr_ident(sp, first);
-                        let id = cx.expr_ident(sp, ident);
-                        let test = cx.expr_binary(sp, BinOpKind::Eq, first_expr, id);
+                        let first_expr = cx.expr_ident(span, first);
+                        let id = cx.expr_ident(span, ident);
+                        let test = cx.expr_binary(span, BinOpKind::Eq, first_expr, id);
                         discriminant_test =
-                            cx.expr_binary(sp, BinOpKind::And, discriminant_test, test)
+                            cx.expr_binary(span, BinOpKind::And, discriminant_test, test)
                     }
                     None => {
                         first_ident = Some(ident);
@@ -1430,8 +1430,8 @@ impl<'a> MethodDef<'a> {
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
-            self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
-            let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
+            self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
+            let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
 
             // Lastly we create an expression which branches on all discriminants being equal
             //  if discriminant_test {
@@ -1445,10 +1445,10 @@ impl<'a> MethodDef<'a> {
             //  else {
             //      <delegated expression referring to __self0_vi, et al.>
             //  }
-            let all_match = cx.expr_match(sp, match_arg, match_arms);
-            let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
+            let all_match = cx.expr_match(span, match_arg, match_arms);
+            let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
             index_let_stmts.push(cx.stmt_expr(arm_expr));
-            cx.expr_block(cx.block(sp, index_let_stmts))
+            cx.expr_block(cx.block(span, index_let_stmts))
         } else if variants.is_empty() {
             // As an additional wrinkle, For a zero-variant enum A,
             // currently the compiler
@@ -1499,16 +1499,16 @@ impl<'a> MethodDef<'a> {
             // derive Debug on such a type could here generate code
             // that needs the feature gate enabled.)
 
-            deriving::call_unreachable(cx, sp)
+            deriving::call_unreachable(cx, span)
         } else {
             // Final wrinkle: the self_args are expressions that deref
             // down to desired places, but we cannot actually deref
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
-            self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
-            let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
-            cx.expr_match(sp, match_arg, match_arms)
+            self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
+            let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
+            cx.expr_match(span, match_arg, match_arms)
         }
     }
 
@@ -1556,11 +1556,9 @@ impl<'a> TraitDef<'a> {
 
         let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
         match (just_spans.is_empty(), named_idents.is_empty()) {
-            (false, false) => cx.span_bug(
-                self.span,
-                "a struct with named and unnamed \
-                                          fields in generic `derive`",
-            ),
+            (false, false) => {
+                cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
+            }
             // named fields
             (_, false) => Named(named_idents),
             // unnamed fields
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index 00d75be4399..7a418003250 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -211,14 +211,6 @@ fn mk_ty_param(
     cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
 }
 
-fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
-    Generics {
-        params,
-        where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
-        span,
-    }
-}
-
 /// Bounds on type parameters.
 #[derive(Clone)]
 pub struct Bounds {
@@ -236,7 +228,7 @@ impl Bounds {
         self_ty: Ident,
         self_generics: &Generics,
     ) -> Generics {
-        let generic_params = self
+        let params = self
             .bounds
             .iter()
             .map(|t| {
@@ -245,7 +237,11 @@ impl Bounds {
             })
             .collect();
 
-        mk_generics(generic_params, span)
+        Generics {
+            params,
+            where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
+            span,
+        }
     }
 }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index fa389a51115..367a5aa7323 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -2,7 +2,7 @@
 
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_ast::{ImplKind, ItemKind, MetaItem};
+use rustc_ast::{Impl, ItemKind, MetaItem};
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
@@ -180,7 +180,7 @@ fn inject_impl_of_structural_trait(
         span,
         Ident::empty(),
         attrs,
-        ItemKind::Impl(Box::new(ImplKind {
+        ItemKind::Impl(Box::new(Impl {
             unsafety: ast::Unsafe::No,
             polarity: ast::ImplPolarity::Positive,
             defaultness: ast::Defaultness::Final,
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index 6de12acfb94..285027fc632 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -80,11 +80,11 @@ pub fn expand_env<'cx>(
     }
 
     let sp = cx.with_def_site_ctxt(sp);
-    let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern);
+    let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern);
     cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
     let e = match value {
         None => {
-            cx.span_err(sp, &msg.as_str());
+            cx.span_err(sp, msg.as_str());
             return DummyResult::any(sp);
         }
         Some(value) => cx.expr_str(sp, value),
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index f0056cb7976..41b56cca1dc 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -11,6 +11,7 @@ use rustc_expand::base::{self, *};
 use rustc_parse_format as parse;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span};
+use smallvec::SmallVec;
 
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
@@ -88,8 +89,8 @@ struct Context<'a, 'b> {
     /// * 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>,
+    /// * `count_args`: `vec![0, 5, 3]`
+    count_args: Vec<usize>,
     /// Relative slot numbers for count arguments.
     count_positions: FxHashMap<usize, usize>,
     /// Number of count slots assigned.
@@ -513,7 +514,7 @@ impl<'a, 'b> Context<'a, 'b> {
                         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_args.push(arg);
                             self.count_positions_count += 1;
                         }
                     }
@@ -527,17 +528,9 @@ impl<'a, 'b> Context<'a, 'b> {
                         self.verify_arg_type(Exact(idx), ty)
                     }
                     None => {
-                        let capture_feature_enabled = self
-                            .ecx
-                            .ecfg
-                            .features
-                            .map_or(false, |features| features.format_args_capture);
-
                         // For the moment capturing variables from format strings expanded from macros is
                         // disabled (see RFC #2795)
-                        let can_capture = capture_feature_enabled && self.is_literal;
-
-                        if can_capture {
+                        if self.is_literal {
                             // Treat this name as a variable to capture from the surrounding scope
                             let idx = self.args.len();
                             self.arg_types.push(Vec::new());
@@ -557,25 +550,17 @@ impl<'a, 'b> Context<'a, 'b> {
                             } else {
                                 self.fmtsp
                             };
-                            let mut err = self.ecx.struct_span_err(sp, &msg[..]);
-
-                            if capture_feature_enabled && !self.is_literal {
-                                err.note(&format!(
-                                    "did you intend to capture a variable `{}` from \
-                                     the surrounding scope?",
-                                    name
-                                ));
-                                err.note(
-                                    "to avoid ambiguity, `format_args!` cannot capture variables \
-                                     when the format string is expanded from a macro",
-                                );
-                            } else if self.ecx.parse_sess().unstable_features.is_nightly_build() {
-                                err.help(&format!(
-                                    "if you intended to capture `{}` from the surrounding scope, add \
-                                     `#![feature(format_args_capture)]` to the crate attributes",
-                                    name
-                                ));
-                            }
+                            let mut err = self.ecx.struct_span_err(sp, &msg);
+
+                            err.note(&format!(
+                                "did you intend to capture a variable `{}` from \
+                                 the surrounding scope?",
+                                name
+                            ));
+                            err.note(
+                                "to avoid ambiguity, `format_args!` cannot capture variables \
+                                 when the format string is expanded from a macro",
+                            );
 
                             err.emit();
                         }
@@ -760,91 +745,95 @@ impl<'a, 'b> Context<'a, 'b> {
     /// 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| Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
-            .collect();
+        let mut original_args = self.args;
+        let mut fmt_args = Vec::with_capacity(
+            self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
+        );
 
         // 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).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 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));
+        // We need to construct a &[ArgumentV1] to pass into the fmt::Arguments
+        // constructor. In general the expressions in this slice might be
+        // permuted from their order in original_args (such as in the case of
+        // "{1} {0}"), or may have multiple entries referring to the same
+        // element of original_args ("{0} {0}").
+        //
+        // The following vector has one item per element of our output slice,
+        // identifying the index of which element of original_args it's passing,
+        // and that argument's type.
+        let mut fmt_arg_index_and_ty = SmallVec::<[(usize, &ArgumentType); 8]>::new();
+        for (i, unique_types) in self.arg_unique_types.iter().enumerate() {
+            fmt_arg_index_and_ty.extend(unique_types.iter().map(|ty| (i, ty)));
         }
+        fmt_arg_index_and_ty.extend(self.count_args.iter().map(|&i| (i, &Count)));
 
-        // 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:
+        // Figure out whether there are permuted or repeated elements. If not,
+        // we can generate simpler code.
         //
-        //      match (&arg0, &arg1) {
-        //          (tmp0, tmp1) => args_array
-        //      }
-        //
-        // It was:
+        // The sequence has no indices out of order or repeated if: for every
+        // adjacent pair of elements, the first one's index is less than the
+        // second one's index.
+        let nicely_ordered =
+            fmt_arg_index_and_ty.array_windows().all(|[(i, _i_ty), (j, _j_ty)]| i < j);
+
+        // We want to emit:
         //
-        //      let tmp0 = &arg0;
-        //      let tmp1 = &arg1;
-        //      args_array
+        //     [ArgumentV1::new(&$arg0, …), ArgumentV1::new(&$arg1, …), …]
         //
-        // 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.
+        // However, it's only legal to do so if $arg0, $arg1, … were written in
+        // exactly that order by the programmer. When arguments are permuted, we
+        // want them evaluated in the order written by the programmer, not in
+        // the order provided to fmt::Arguments. When arguments are repeated, we
+        // want the expression evaluated only once.
         //
-        // Note, it may also very well be transformed to:
+        // Thus in the not nicely ordered case we emit the following instead:
         //
-        //      match arg0 {
-        //          ref tmp0 => {
-        //              match arg1 => {
-        //                  ref tmp1 => args_array } } }
+        //     match (&$arg0, &$arg1, …) {
+        //         args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …]
+        //     }
         //
-        // But the nested match expression is proved to perform not as well
-        // as series of let's; the first approach does.
-        let args_match = {
-            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));
-            self.ecx.expr_match(self.macsp, head, vec![arm])
-        };
+        // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty.
+        for (arg_index, arg_ty) in fmt_arg_index_and_ty {
+            let e = &mut original_args[arg_index];
+            let span = e.span;
+            let arg = if nicely_ordered {
+                let expansion_span = e.span.with_ctxt(self.macsp.ctxt());
+                // The indices are strictly ordered so e has not been taken yet.
+                self.ecx.expr_addr_of(expansion_span, P(e.take()))
+            } else {
+                let def_site = self.ecx.with_def_site_ctxt(span);
+                let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::args, def_site));
+                let member = Ident::new(sym::integer(arg_index), def_site);
+                self.ecx.expr(def_site, ast::ExprKind::Field(args_tuple, member))
+            };
+            fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg));
+        }
 
-        let args_slice = self.ecx.expr_addr_of(self.macsp, args_match);
+        let args_array = self.ecx.expr_vec(self.macsp, fmt_args);
+        let args_slice = self.ecx.expr_addr_of(
+            self.macsp,
+            if nicely_ordered {
+                args_array
+            } else {
+                // In the !nicely_ordered case, none of the exprs were moved
+                // away in the previous loop.
+                //
+                // This uses the arg span for `&arg` so that borrowck errors
+                // point to the specific expression passed to the macro (the
+                // span is otherwise unavailable in the MIR used by borrowck).
+                let heads = original_args
+                    .into_iter()
+                    .map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e))
+                    .collect();
+
+                let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp));
+                let arm = self.ecx.arm(self.macsp, pat, args_array);
+                let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
+                self.ecx.expr_match(self.macsp, head, vec![arm])
+            },
+        );
 
         // Now create the fmt::Arguments struct with all our locals we created.
         let (fn_name, fn_args) = if self.all_pieces_simple {
@@ -877,10 +866,9 @@ impl<'a, 'b> Context<'a, 'b> {
         macsp: Span,
         mut sp: Span,
         ty: &ArgumentType,
-        arg: Ident,
+        arg: P<ast::Expr>,
     ) -> 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_,
@@ -889,11 +877,21 @@ impl<'a, 'b> Context<'a, 'b> {
                 return ecx.expr_call_global(macsp, path, vec![arg]);
             }
         };
+        let new_fn_name = match trait_ {
+            "Display" => "new_display",
+            "Debug" => "new_debug",
+            "LowerExp" => "new_lower_exp",
+            "UpperExp" => "new_upper_exp",
+            "Octal" => "new_octal",
+            "Pointer" => "new_pointer",
+            "Binary" => "new_binary",
+            "LowerHex" => "new_lower_hex",
+            "UpperHex" => "new_upper_hex",
+            _ => unreachable!(),
+        };
 
-        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)])
+        let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]);
+        ecx.expr_call_global(sp, path, vec![arg])
     }
 }
 
@@ -983,7 +981,7 @@ pub fn expand_preparsed_format_args(
         ast::StrStyle::Raw(raw) => Some(raw as usize),
     };
 
-    let fmt_str = &fmt_str.as_str(); // for the suggestions below
+    let fmt_str = fmt_str.as_str(); // for the suggestions below
     let fmt_snippet = ecx.source_map().span_to_snippet(fmt_sp).ok();
     let mut parser = parse::Parser::new(
         fmt_str,
@@ -1023,8 +1021,9 @@ pub fn expand_preparsed_format_args(
             e.note(&note);
         }
         if let Some((label, span)) = err.secondary_label {
-            let sp = fmt_span.from_inner(span);
-            e.span_label(sp, label);
+            if efmt_kind_is_lit {
+                e.span_label(fmt_span.from_inner(span), label);
+            }
         }
         e.emit();
         return DummyResult::raw_expr(sp, true);
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index bfddd7073ff..ecd16736e7c 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -7,28 +7,29 @@ pub(crate) mod printf {
     pub enum Substitution<'a> {
         /// A formatted output substitution with its internal byte offset.
         Format(Format<'a>),
-        /// A literal `%%` escape.
-        Escape,
+        /// A literal `%%` escape, with its start and end indices.
+        Escape((usize, usize)),
     }
 
     impl<'a> Substitution<'a> {
         pub fn as_str(&self) -> &str {
             match *self {
                 Substitution::Format(ref fmt) => fmt.span,
-                Substitution::Escape => "%%",
+                Substitution::Escape(_) => "%%",
             }
         }
 
         pub fn position(&self) -> Option<InnerSpan> {
             match *self {
                 Substitution::Format(ref fmt) => Some(fmt.position),
-                _ => None,
+                Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)),
             }
         }
 
         pub fn set_position(&mut self, start: usize, end: usize) {
-            if let Substitution::Format(ref mut fmt) = self {
-                fmt.position = InnerSpan::new(start, end);
+            match self {
+                Substitution::Format(ref mut fmt) => fmt.position = InnerSpan::new(start, end),
+                Substitution::Escape(ref mut pos) => *pos = (start, end),
             }
         }
 
@@ -39,7 +40,7 @@ pub(crate) mod printf {
         pub fn translate(&self) -> Result<String, Option<String>> {
             match *self {
                 Substitution::Format(ref fmt) => fmt.translate(),
-                Substitution::Escape => Err(None),
+                Substitution::Escape(_) => Err(None),
             }
         }
     }
@@ -304,14 +305,9 @@ pub(crate) mod printf {
         fn next(&mut self) -> Option<Self::Item> {
             let (mut sub, tail) = parse_next_substitution(self.s)?;
             self.s = tail;
-            match sub {
-                Substitution::Format(_) => {
-                    if let Some(inner_span) = sub.position() {
-                        sub.set_position(inner_span.start + self.pos, inner_span.end + self.pos);
-                        self.pos += inner_span.end;
-                    }
-                }
-                Substitution::Escape => self.pos += 2,
+            if let Some(InnerSpan { start, end }) = sub.position() {
+                sub.set_position(start + self.pos, end + self.pos);
+                self.pos += end;
             }
             Some(sub)
         }
@@ -340,7 +336,7 @@ pub(crate) mod printf {
         let at = {
             let start = s.find('%')?;
             if let '%' = s[start + 1..].chars().next()? {
-                return Some((Substitution::Escape, &s[start + 2..]));
+                return Some((Substitution::Escape((start, start + 2)), &s[start + 2..]));
             }
 
             Cur::new_at(s, start)
diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
index 1336aab7316..fc7442470ac 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
@@ -13,9 +13,9 @@ macro_rules! assert_eq_pnsat {
 fn test_escape() {
     assert_eq!(pns("has no escapes"), None);
     assert_eq!(pns("has no escapes, either %"), None);
-    assert_eq!(pns("*so* has a %% escape"), Some((S::Escape, " escape")));
-    assert_eq!(pns("%% leading escape"), Some((S::Escape, " leading escape")));
-    assert_eq!(pns("trailing escape %%"), Some((S::Escape, "")));
+    assert_eq!(pns("*so* has a %% escape"), Some((S::Escape((11, 13)), " escape")));
+    assert_eq!(pns("%% leading escape"), Some((S::Escape((0, 2)), " leading escape")));
+    assert_eq!(pns("trailing escape %%"), Some((S::Escape((16, 18)), "")));
 }
 
 #[test]
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 3f71ee6f489..a433876147f 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -5,7 +5,7 @@ use rustc_ast::expand::allocator::{
 };
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{FnKind, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
@@ -84,13 +84,13 @@ impl AllocFnFactory<'_, '_> {
         let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
         let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
         let sig = FnSig { decl, header, span: self.span };
-        let block = Some(self.cx.block_expr(output_expr));
-        let kind = ItemKind::Fn(Box::new(FnKind(
-            ast::Defaultness::Final,
+        let body = Some(self.cx.block_expr(output_expr));
+        let kind = ItemKind::Fn(Box::new(Fn {
+            defaultness: ast::Defaultness::Final,
             sig,
-            Generics::default(),
-            block,
-        )));
+            generics: Generics::default(),
+            body,
+        }));
         let item = self.cx.item(
             self.span,
             Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index d1d276930b9..6c16c285492 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -2,11 +2,12 @@
 //! injecting code into the crate before it is lowered to HIR.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
-#![feature(iter_zip)]
+#![feature(is_sorted)]
 #![feature(nll)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
@@ -20,13 +21,13 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
 use rustc_span::symbol::sym;
 
-mod asm;
 mod assert;
 mod cfg;
 mod cfg_accessible;
 mod cfg_eval;
 mod compile_error;
 mod concat;
+mod concat_bytes;
 mod concat_idents;
 mod derive;
 mod deriving;
@@ -34,7 +35,6 @@ mod env;
 mod format;
 mod format_foreign;
 mod global_allocator;
-mod llvm_asm;
 mod log_syntax;
 mod panic;
 mod source_util;
@@ -42,6 +42,7 @@ mod test;
 mod trace_macros;
 mod util;
 
+pub mod asm;
 pub mod cmdline_attrs;
 pub mod proc_macro_harness;
 pub mod standard_library_imports;
@@ -65,6 +66,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         cfg: cfg::expand_cfg,
         column: source_util::expand_column,
         compile_error: compile_error::expand_compile_error,
+        concat_bytes: concat_bytes::expand_concat_bytes,
         concat_idents: concat_idents::expand_concat_idents,
         concat: concat::expand_concat,
         env: env::expand_env,
@@ -77,7 +79,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         include_str: source_util::expand_include_str,
         include: source_util::expand_include,
         line: source_util::expand_line,
-        llvm_asm: llvm_asm::expand_llvm_asm,
         log_syntax: log_syntax::expand_log_syntax,
         module_path: source_util::expand_mod,
         option_env: env::expand_option_env,
diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs
deleted file mode 100644
index d72bfa660e5..00000000000
--- a/compiler/rustc_builtin_macros/src/llvm_asm.rs
+++ /dev/null
@@ -1,303 +0,0 @@
-// Llvm-style inline assembly support.
-//
-use State::*;
-
-use rustc_ast as ast;
-use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token};
-use rustc_ast::tokenstream::{self, TokenStream};
-use rustc_ast::LlvmAsmDialect;
-use rustc_errors::{struct_span_err, DiagnosticBuilder, PResult};
-use rustc_expand::base::*;
-use rustc_parse::parser::Parser;
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
-
-enum State {
-    Asm,
-    Outputs,
-    Inputs,
-    Clobbers,
-    Options,
-    StateNone,
-}
-
-impl State {
-    fn next(&self) -> State {
-        match *self {
-            Asm => Outputs,
-            Outputs => Inputs,
-            Inputs => Clobbers,
-            Clobbers => Options,
-            Options => StateNone,
-            StateNone => StateNone,
-        }
-    }
-}
-
-const OPTIONS: &[Symbol] = &[sym::volatile, sym::alignstack, sym::intel];
-
-pub fn expand_llvm_asm<'cx>(
-    cx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
-    let mut inline_asm = match parse_inline_asm(cx, sp, tts) {
-        Ok(Some(inline_asm)) => inline_asm,
-        Ok(None) => return DummyResult::any(sp),
-        Err(mut err) => {
-            err.emit();
-            return DummyResult::any(sp);
-        }
-    };
-
-    // If there are no outputs, the inline assembly is executed just for its side effects,
-    // so ensure that it is volatile
-    if inline_asm.outputs.is_empty() {
-        inline_asm.volatile = true;
-    }
-
-    MacEager::expr(P(ast::Expr {
-        id: ast::DUMMY_NODE_ID,
-        kind: ast::ExprKind::LlvmInlineAsm(P(inline_asm)),
-        span: cx.with_def_site_ctxt(sp),
-        attrs: ast::AttrVec::new(),
-        tokens: None,
-    }))
-}
-
-fn parse_asm_str<'a>(p: &mut Parser<'a>) -> PResult<'a, Symbol> {
-    match p.parse_str_lit() {
-        Ok(str_lit) => Ok(str_lit.symbol_unescaped),
-        Err(opt_lit) => {
-            let span = opt_lit.map_or(p.token.span, |lit| lit.span);
-            let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
-            err.span_label(span, "not a string literal");
-            Err(err)
-        }
-    }
-}
-
-fn parse_inline_asm<'a>(
-    cx: &mut ExtCtxt<'a>,
-    sp: Span,
-    tts: TokenStream,
-) -> Result<Option<ast::LlvmInlineAsm>, DiagnosticBuilder<'a>> {
-    // Split the tts before the first colon, to avoid `llvm_asm!("x": y)`  being
-    // parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
-    let first_colon = tts
-        .trees()
-        .position(|tt| {
-            matches!(
-                tt,
-                tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
-            )
-        })
-        .unwrap_or(tts.len());
-    let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());
-    let mut asm = kw::Empty;
-    let mut asm_str_style = None;
-    let mut outputs = Vec::new();
-    let mut inputs = Vec::new();
-    let mut clobs = Vec::new();
-    let mut volatile = false;
-    let mut alignstack = false;
-    let mut dialect = LlvmAsmDialect::Att;
-
-    let mut state = Asm;
-
-    'statement: loop {
-        match state {
-            Asm => {
-                if asm_str_style.is_some() {
-                    // If we already have a string with instructions,
-                    // ending up in Asm state again is an error.
-                    return Err(struct_span_err!(
-                        cx.sess.parse_sess.span_diagnostic,
-                        sp,
-                        E0660,
-                        "malformed inline assembly"
-                    ));
-                }
-                // Nested parser, stop before the first colon (see above).
-                let mut p2 = cx.new_parser_from_tts(tts.trees().take(first_colon).collect());
-
-                if p2.token == token::Eof {
-                    let mut err =
-                        cx.struct_span_err(sp, "macro requires a string literal as an argument");
-                    err.span_label(sp, "string literal required");
-                    return Err(err);
-                }
-
-                let expr = p2.parse_expr()?;
-                let (s, style) =
-                    match expr_to_string(cx, expr, "inline assembly must be a string literal") {
-                        Some((s, st)) => (s, st),
-                        None => return Ok(None),
-                    };
-
-                // This is most likely malformed.
-                if p2.token != token::Eof {
-                    let mut extra_tts = p2.parse_all_token_trees()?;
-                    extra_tts.extend(tts.trees().skip(first_colon));
-                    p = cx.new_parser_from_tts(extra_tts.into_iter().collect());
-                }
-
-                asm = s;
-                asm_str_style = Some(style);
-            }
-            Outputs => {
-                while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
-                    if !outputs.is_empty() {
-                        p.eat(&token::Comma);
-                    }
-
-                    let constraint = parse_asm_str(&mut p)?;
-
-                    let span = p.prev_token.span;
-
-                    p.expect(&token::OpenDelim(token::Paren))?;
-                    let expr = p.parse_expr()?;
-                    p.expect(&token::CloseDelim(token::Paren))?;
-
-                    // Expands a read+write operand into two operands.
-                    //
-                    // Use '+' modifier when you want the same expression
-                    // to be both an input and an output at the same time.
-                    // It's the opposite of '=&' which means that the memory
-                    // cannot be shared with any other operand (usually when
-                    // a register is clobbered early.)
-                    let constraint_str = constraint.as_str();
-                    let mut ch = constraint_str.chars();
-                    let output = match ch.next() {
-                        Some('=') => None,
-                        Some('+') => Some(Symbol::intern(&format!("={}", ch.as_str()))),
-                        _ => {
-                            struct_span_err!(
-                                cx.sess.parse_sess.span_diagnostic,
-                                span,
-                                E0661,
-                                "output operand constraint lacks '=' or '+'"
-                            )
-                            .emit();
-                            None
-                        }
-                    };
-
-                    let is_rw = output.is_some();
-                    let is_indirect = constraint_str.contains('*');
-                    outputs.push(ast::LlvmInlineAsmOutput {
-                        constraint: output.unwrap_or(constraint),
-                        expr,
-                        is_rw,
-                        is_indirect,
-                    });
-                }
-            }
-            Inputs => {
-                while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
-                    if !inputs.is_empty() {
-                        p.eat(&token::Comma);
-                    }
-
-                    let constraint = parse_asm_str(&mut p)?;
-
-                    if constraint.as_str().starts_with('=') {
-                        struct_span_err!(
-                            cx.sess.parse_sess.span_diagnostic,
-                            p.prev_token.span,
-                            E0662,
-                            "input operand constraint contains '='"
-                        )
-                        .emit();
-                    } else if constraint.as_str().starts_with('+') {
-                        struct_span_err!(
-                            cx.sess.parse_sess.span_diagnostic,
-                            p.prev_token.span,
-                            E0663,
-                            "input operand constraint contains '+'"
-                        )
-                        .emit();
-                    }
-
-                    p.expect(&token::OpenDelim(token::Paren))?;
-                    let input = p.parse_expr()?;
-                    p.expect(&token::CloseDelim(token::Paren))?;
-
-                    inputs.push((constraint, input));
-                }
-            }
-            Clobbers => {
-                while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
-                    if !clobs.is_empty() {
-                        p.eat(&token::Comma);
-                    }
-
-                    let s = parse_asm_str(&mut p)?;
-
-                    if OPTIONS.iter().any(|&opt| s == opt) {
-                        cx.span_warn(p.prev_token.span, "expected a clobber, found an option");
-                    } else if s.as_str().starts_with('{') || s.as_str().ends_with('}') {
-                        struct_span_err!(
-                            cx.sess.parse_sess.span_diagnostic,
-                            p.prev_token.span,
-                            E0664,
-                            "clobber should not be surrounded by braces"
-                        )
-                        .emit();
-                    }
-
-                    clobs.push(s);
-                }
-            }
-            Options => {
-                let option = parse_asm_str(&mut p)?;
-
-                if option == sym::volatile {
-                    // Indicates that the inline assembly has side effects
-                    // and must not be optimized out along with its outputs.
-                    volatile = true;
-                } else if option == sym::alignstack {
-                    alignstack = true;
-                } else if option == sym::intel {
-                    dialect = LlvmAsmDialect::Intel;
-                } else {
-                    cx.span_warn(p.prev_token.span, "unrecognized option");
-                }
-
-                if p.token == token::Comma {
-                    p.eat(&token::Comma);
-                }
-            }
-            StateNone => (),
-        }
-
-        loop {
-            // MOD_SEP is a double colon '::' without space in between.
-            // When encountered, the state must be advanced twice.
-            match (&p.token.kind, state.next(), state.next().next()) {
-                (&token::Colon, StateNone, _) | (&token::ModSep, _, StateNone) => {
-                    p.bump();
-                    break 'statement;
-                }
-                (&token::Colon, st, _) | (&token::ModSep, _, st) => {
-                    p.bump();
-                    state = st;
-                }
-                (&token::Eof, ..) => break 'statement,
-                _ => break,
-            }
-        }
-    }
-
-    Ok(Some(ast::LlvmInlineAsm {
-        asm,
-        asm_str_style: asm_str_style.unwrap(),
-        outputs,
-        inputs,
-        clobbers: clobs,
-        volatile,
-        alignstack,
-        dialect,
-    }))
-}
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index bbca07085ea..c08b141b557 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -1,6 +1,6 @@
 /// The expansion from a test function to the appropriate test struct for libtest
 /// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
-use crate::util::check_builtin_macro_attribute;
+use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
 
 use rustc_ast as ast;
 use rustc_ast::attr;
@@ -27,6 +27,7 @@ pub fn expand_test_case(
     anno_item: Annotatable,
 ) -> Vec<Annotatable> {
     check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
+    warn_on_duplicate_attribute(&ecx, &anno_item, sym::test_case);
 
     if !ecx.ecfg.should_test {
         return vec![];
@@ -55,6 +56,7 @@ pub fn expand_test(
     item: Annotatable,
 ) -> Vec<Annotatable> {
     check_builtin_macro_attribute(cx, meta_item, sym::test);
+    warn_on_duplicate_attribute(&cx, &item, sym::test);
     expand_test_or_bench(cx, attr_sp, item, false)
 }
 
@@ -65,6 +67,7 @@ pub fn expand_bench(
     item: Annotatable,
 ) -> Vec<Annotatable> {
     check_builtin_macro_attribute(cx, meta_item, sym::bench);
+    warn_on_duplicate_attribute(&cx, &item, sym::bench);
     expand_test_or_bench(cx, attr_sp, item, true)
 }
 
@@ -429,7 +432,7 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
 fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
     let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
     let sd = &cx.sess.parse_sess.span_diagnostic;
-    if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, ref generics, _)) = i.kind {
+    if let ast::ItemKind::Fn(box ast::Fn { ref sig, ref generics, .. }) = i.kind {
         if let ast::Unsafe::Yes(span) = sig.header.unsafety {
             sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
                 .span_label(span, "`unsafe` because of this")
@@ -478,7 +481,7 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
 }
 
 fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
-    let has_sig = if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) = i.kind {
+    let has_sig = if let ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) = i.kind {
         // N.B., inadequate check, but we're running
         // well before resolve, can't get too deep.
         sig.decl.inputs.len() == 1
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index d791677cb8e..418729e7843 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -84,9 +84,35 @@ struct TestHarnessGenerator<'a> {
     tests: Vec<Test>,
 }
 
+impl TestHarnessGenerator<'_> {
+    fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec<Test>) {
+        let mut tests = mem::replace(&mut self.tests, prev_tests);
+
+        if !tests.is_empty() {
+            // Create an identifier that will hygienically resolve the test
+            // case name, even in another module.
+            let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
+                span,
+                AstPass::TestHarness,
+                &[],
+                Some(node_id),
+            );
+            for test in &mut tests {
+                // See the comment on `mk_main` for why we're using
+                // `apply_mark` directly.
+                test.ident.span =
+                    test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
+            }
+            self.cx.test_cases.extend(tests);
+        }
+    }
+}
+
 impl<'a> MutVisitor for TestHarnessGenerator<'a> {
     fn visit_crate(&mut self, c: &mut ast::Crate) {
+        let prev_tests = mem::take(&mut self.tests);
         noop_visit_crate(c, self);
+        self.add_test_cases(ast::CRATE_NODE_ID, c.span, prev_tests);
 
         // Create a main function to run our tests
         c.items.push(mk_main(&mut self.cx));
@@ -103,34 +129,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
 
         // We don't want to recurse into anything other than mods, since
         // mods or tests inside of functions will break things
-        if let ast::ItemKind::Mod(..) = item.kind {
-            let tests = mem::take(&mut self.tests);
+        if let ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) = item.kind {
+            let prev_tests = mem::take(&mut self.tests);
             noop_visit_item_kind(&mut item.kind, self);
-            let mut tests = mem::replace(&mut self.tests, tests);
-
-            if !tests.is_empty() {
-                let parent =
-                    if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
-                // Create an identifier that will hygienically resolve the test
-                // case name, even in another module.
-                let inner_span = match item.kind {
-                    ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
-                    _ => unreachable!(),
-                };
-                let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
-                    inner_span,
-                    AstPass::TestHarness,
-                    &[],
-                    Some(parent),
-                );
-                for test in &mut tests {
-                    // See the comment on `mk_main` for why we're using
-                    // `apply_mark` directly.
-                    test.ident.span =
-                        test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
-                }
-                self.cx.test_cases.extend(tests);
-            }
+            self.add_test_cases(item.id, span, prev_tests);
         }
         smallvec![P(item)]
     }
@@ -146,7 +148,7 @@ fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPoin
             } else if sess.contains_name(&item.attrs, sym::rustc_main) {
                 EntryPointType::MainAttr
             } else if item.ident.name == sym::main {
-                if depth == 1 {
+                if depth == 0 {
                     // This is a top-level function so can be 'main'
                     EntryPointType::MainNamed
                 } else {
@@ -313,13 +315,13 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
 
     let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty));
     let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
-    let def = ast::Defaultness::Final;
-    let main = ast::ItemKind::Fn(Box::new(ast::FnKind(
-        def,
+    let defaultness = ast::Defaultness::Final;
+    let main = ast::ItemKind::Fn(Box::new(ast::Fn {
+        defaultness,
         sig,
-        ast::Generics::default(),
-        Some(main_body),
-    )));
+        generics: ast::Generics::default(),
+        body: Some(main_body),
+    }));
 
     // Honor the reexport_test_harness_main attribute
     let main_id = match cx.reexport_test_harness_main {
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index 01ea80c4c8a..527fe50eff0 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -1,6 +1,7 @@
-use rustc_ast::MetaItem;
-use rustc_expand::base::ExtCtxt;
+use rustc_ast::{Attribute, MetaItem};
+use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_feature::AttributeTemplate;
+use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
 use rustc_parse::validate_attr;
 use rustc_span::Symbol;
 
@@ -10,3 +11,33 @@ pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, na
     let attr = ecx.attribute(meta_item.clone());
     validate_attr::check_builtin_attribute(&ecx.sess.parse_sess, &attr, name, template);
 }
+
+/// Emit a warning if the item is annotated with the given attribute. This is used to diagnose when
+/// an attribute may have been mistakenly duplicated.
+pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) {
+    let attrs: Option<&[Attribute]> = match item {
+        Annotatable::Item(item) => Some(&item.attrs),
+        Annotatable::TraitItem(item) => Some(&item.attrs),
+        Annotatable::ImplItem(item) => Some(&item.attrs),
+        Annotatable::ForeignItem(item) => Some(&item.attrs),
+        Annotatable::Expr(expr) => Some(&expr.attrs),
+        Annotatable::Arm(arm) => Some(&arm.attrs),
+        Annotatable::ExprField(field) => Some(&field.attrs),
+        Annotatable::PatField(field) => Some(&field.attrs),
+        Annotatable::GenericParam(param) => Some(&param.attrs),
+        Annotatable::Param(param) => Some(&param.attrs),
+        Annotatable::FieldDef(def) => Some(&def.attrs),
+        Annotatable::Variant(variant) => Some(&variant.attrs),
+        _ => None,
+    };
+    if let Some(attrs) = attrs {
+        if let Some(attr) = ecx.sess.find_by_name(attrs, name) {
+            ecx.parse_sess().buffer_lint(
+                DUPLICATE_MACRO_ATTRIBUTES,
+                attr.span,
+                ecx.current_expansion.lint_node_id,
+                "duplicated attribute",
+            );
+        }
+    }
+}