diff --git a/Cargo.lock b/Cargo.lock
index 395f5a127bd3d..b8c8466ffe9b5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -321,7 +321,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.65.0"
+version = "0.66.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -4011,6 +4011,7 @@ dependencies = [
  "rustc_hir",
  "rustc_incremental",
  "rustc_lint",
+ "rustc_macros",
  "rustc_metadata",
  "rustc_middle",
  "rustc_mir_build",
@@ -4359,6 +4360,7 @@ dependencies = [
  "rustc_serialize",
  "rustc_session",
  "rustc_span",
+ "rustc_target",
  "tracing",
 ]
 
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 3d8eee6f5974a..268b0527b1cb2 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1689,7 +1689,7 @@ pub enum StrStyle {
 #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct Lit {
     /// The original literal token as written in source code.
-    pub token: token::Lit,
+    pub token_lit: token::Lit,
     /// The "semantic" representation of the literal lowered from the original tokens.
     /// Strings are unescaped, hexadecimal forms are eliminated, etc.
     /// FIXME: Remove this and only create the semantic representation during lowering to HIR.
@@ -1717,7 +1717,7 @@ impl StrLit {
             StrStyle::Raw(n) => token::StrRaw(n),
         };
         Lit {
-            token: token::Lit::new(token_kind, self.symbol, self.suffix),
+            token_lit: token::Lit::new(token_kind, self.symbol, self.suffix),
             span: self.span,
             kind: LitKind::Str(self.symbol_unescaped, self.style),
         }
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index bc4f183d9b111..0d114f1366c4d 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -184,13 +184,7 @@ impl MetaItem {
     }
 
     pub fn value_str(&self) -> Option<Symbol> {
-        match self.kind {
-            MetaItemKind::NameValue(ref v) => match v.kind {
-                LitKind::Str(ref s, _) => Some(*s),
-                _ => None,
-            },
-            _ => None,
-        }
+        self.kind.value_str()
     }
 
     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 9c18f55c03b4d..e6351d89c6c31 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -23,7 +23,7 @@ pub enum LitError {
 
 impl LitKind {
     /// Converts literal token into a semantic literal.
-    pub fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
+    pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
         let token::Lit { kind, symbol, suffix } = lit;
         if suffix.is_some() && !kind.may_have_suffix() {
             return Err(LitError::InvalidSuffix);
@@ -153,7 +153,7 @@ impl LitKind {
     /// Attempts to recover a token from semantic literal.
     /// This function is used when the original token doesn't exist (e.g. the literal is created
     /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
-    pub fn to_lit_token(&self) -> token::Lit {
+    pub fn to_token_lit(&self) -> token::Lit {
         let (kind, symbol, suffix) = match *self {
             LitKind::Str(symbol, ast::StrStyle::Cooked) => {
                 // Don't re-intern unless the escaped string is different.
@@ -208,8 +208,8 @@ impl LitKind {
 
 impl Lit {
     /// Converts literal token into an AST literal.
-    pub fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
-        Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
+    pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result<Lit, LitError> {
+        Ok(Lit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span })
     }
 
     /// Converts arbitrary token into an AST literal.
@@ -232,21 +232,21 @@ impl Lit {
             _ => return Err(LitError::NotLiteral),
         };
 
-        Lit::from_lit_token(lit, token.span)
+        Lit::from_token_lit(lit, token.span)
     }
 
     /// Attempts to recover an AST literal from semantic literal.
     /// This function is used when the original token doesn't exist (e.g. the literal is created
     /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
     pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit {
-        Lit { token: kind.to_lit_token(), kind, span }
+        Lit { token_lit: kind.to_token_lit(), kind, span }
     }
 
     /// Losslessly convert an AST literal into a token.
     pub fn to_token(&self) -> Token {
-        let kind = match self.token.kind {
-            token::Bool => token::Ident(self.token.symbol, false),
-            _ => token::Literal(self.token),
+        let kind = match self.token_lit.kind {
+            token::Bool => token::Ident(self.token_lit.symbol, false),
+            _ => token::Literal(self.token_lit),
         };
         Token::new(kind, self.span)
     }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 5f5667ce9055f..1ac1d689efbdb 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -927,7 +927,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     lit.clone()
                 } else {
                     Lit {
-                        token: token::Lit::new(token::LitKind::Err, kw::Empty, None),
+                        token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None),
                         kind: LitKind::Err(kw::Empty),
                         span: DUMMY_SP,
                     }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index c454034efa735..8749a13c5dde1 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -372,7 +372,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
 
     fn print_literal(&mut self, lit: &ast::Lit) {
         self.maybe_print_comment(lit.span.lo());
-        self.word(lit.token.to_string())
+        self.word(lit.token_lit.to_string())
     }
 
     fn print_string(&mut self, st: &str, style: ast::StrStyle) {
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index a1afec410c1c5..c0f35d122f8e6 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -1,6 +1,5 @@
 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};
 
@@ -185,5 +184,5 @@ pub fn expand_concat_bytes(
         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))))
+    base::MacEager::expr(cx.expr_byte_str(sp, accumulator))
 }
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index d3de10ca4a2e9..467ac34ded942 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -126,9 +126,9 @@ 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()) => {
-            format!("try using `#[derive({})]`", lit.token.symbol)
+    let help_msg = match lit.token_lit.kind {
+        token::Str if rustc_lexer::is_ident(lit.token_lit.symbol.as_str()) => {
+            format!("try using `#[derive({})]`", lit.token_lit.symbol)
         }
         _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
     };
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index ceef893e862eb..5ab70e441b814 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -52,7 +52,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
 
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
-    let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
+    let name = cx.expr_str(span, ident.name);
     let fmt = substr.nonselflike_args[0].clone();
 
     // Struct and tuples are similar enough that we use the same code for both,
@@ -89,10 +89,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         for i in 0..fields.len() {
             let field = &fields[i];
             if is_struct {
-                let name = cx.expr_lit(
-                    field.span,
-                    ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
-                );
+                let name = cx.expr_str(field.span, field.name.unwrap().name);
                 args.push(name);
             }
             // Use an extra indirection to make sure this works for unsized types.
@@ -108,10 +105,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
 
         for field in fields {
             if is_struct {
-                name_exprs.push(cx.expr_lit(
-                    field.span,
-                    ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
-                ));
+                name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name));
             }
 
             // Use an extra indirection to make sure this works for unsized types.
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 53c13873b1016..08026c9d35784 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -923,7 +923,7 @@ impl<'a, 'b> Context<'a, 'b> {
                 }
 
                 // Build the format
-                let fill = self.ecx.expr_lit(sp, ast::LitKind::Char(fill));
+                let fill = self.ecx.expr_char(sp, fill);
                 let align = |name| {
                     let mut p = Context::rtpath(self.ecx, sym::Alignment);
                     p.push(Ident::new(name, sp));
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 8bf3a0799b638..d78bbc3c93226 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -216,7 +216,7 @@ pub fn expand_include_bytes(
         }
     };
     match cx.source_map().load_binary_file(&file) {
-        Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(bytes.into()))),
+        Ok(bytes) => base::MacEager::expr(cx.expr_byte_str(sp, bytes)),
         Err(e) => {
             cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp)
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index dbd55590e5c08..2930d09d71f1a 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::profiling::TimingGuard;
 use rustc_data_structures::profiling::VerboseTimingGuard;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
-use rustc_errors::{DiagnosticId, FatalError, Handler, Level};
+use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
 use rustc_fs_util::link_or_copy;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_incremental::{
@@ -1740,6 +1740,16 @@ impl SharedEmitter {
     }
 }
 
+impl Translate for SharedEmitter {
+    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+        None
+    }
+
+    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
+        panic!("shared emitter attempted to translate a diagnostic");
+    }
+}
+
 impl Emitter for SharedEmitter {
     fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
         let fluent_args = self.to_fluent_args(diag.args());
@@ -1761,14 +1771,6 @@ impl Emitter for SharedEmitter {
     fn source_map(&self) -> Option<&Lrc<SourceMap>> {
         None
     }
-
-    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
-        None
-    }
-
-    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
-        panic!("shared emitter attempted to translate a diagnostic");
-    }
 }
 
 impl SharedEmitterMain {
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index d563e35f9102d..c8557d172ed43 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -534,7 +534,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             let mut non_zst_field = None;
                             for i in 0..receiver.layout.fields.count() {
                                 let field = self.operand_field(&receiver, i)?;
-                                if !field.layout.is_zst() {
+                                let zst =
+                                    field.layout.is_zst() && field.layout.align.abi.bytes() == 1;
+                                if !zst {
                                     assert!(
                                         non_zst_field.is_none(),
                                         "multiple non-ZST fields in dyn receiver type {}",
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 52952a7932dbc..258780ecaea26 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -56,9 +56,7 @@ cfg_if! {
             pub fn new(v: T) -> Self {
                 Atomic(Cell::new(v))
             }
-        }
 
-        impl<T: Copy> Atomic<T> {
             #[inline]
             pub fn into_inner(self) -> T {
                 self.0.into_inner()
diff --git a/compiler/rustc_error_messages/locales/en-US/interface.ftl b/compiler/rustc_error_messages/locales/en-US/interface.ftl
new file mode 100644
index 0000000000000..2c05abd8c0996
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/interface.ftl
@@ -0,0 +1,6 @@
+interface_ferris_identifier =
+    Ferris cannot be used as an identifier
+    .suggestion = try using their name instead
+
+interface_emoji_identifier =
+    identifiers cannot contain emoji: `{$ident}`
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 9e73a39980927..6ae4dab3a35eb 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -34,6 +34,7 @@ fluent_messages! {
     builtin_macros => "../locales/en-US/builtin_macros.ftl",
     const_eval => "../locales/en-US/const_eval.ftl",
     expand => "../locales/en-US/expand.ftl",
+    interface => "../locales/en-US/interface.ftl",
     lint => "../locales/en-US/lint.ftl",
     parser => "../locales/en-US/parser.ftl",
     passes => "../locales/en-US/passes.ftl",
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 3df562c7edac7..b32fc3c719bbd 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -7,6 +7,7 @@
 
 use crate::emitter::FileWithAnnotatedLines;
 use crate::snippet::Line;
+use crate::translation::Translate;
 use crate::{
     CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
     LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
@@ -32,6 +33,16 @@ pub struct AnnotateSnippetEmitterWriter {
     macro_backtrace: bool,
 }
 
+impl Translate for AnnotateSnippetEmitterWriter {
+    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+        self.fluent_bundle.as_ref()
+    }
+
+    fn fallback_fluent_bundle(&self) -> &FluentBundle {
+        &**self.fallback_bundle
+    }
+}
+
 impl Emitter for AnnotateSnippetEmitterWriter {
     /// The entry point for the diagnostics generation
     fn emit_diagnostic(&mut self, diag: &Diagnostic) {
@@ -63,14 +74,6 @@ impl Emitter for AnnotateSnippetEmitterWriter {
         self.source_map.as_ref()
     }
 
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
-        self.fluent_bundle.as_ref()
-    }
-
-    fn fallback_fluent_bundle(&self) -> &FluentBundle {
-        &**self.fallback_bundle
-    }
-
     fn should_show_explain(&self) -> bool {
         !self.short_message
     }
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 753e2f07c042e..6c1bfcb9919eb 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -14,10 +14,10 @@ use rustc_span::{FileLines, SourceFile, Span};
 
 use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
 use crate::styled_buffer::StyledBuffer;
+use crate::translation::Translate;
 use crate::{
-    CodeSuggestion, Diagnostic, DiagnosticArg, DiagnosticId, DiagnosticMessage, FluentBundle,
-    Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight,
-    SuggestionStyle,
+    CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
+    LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
 };
 
 use rustc_lint_defs::pluralize;
@@ -200,7 +200,7 @@ impl Margin {
 const ANONYMIZED_LINE_NUM: &str = "LL";
 
 /// Emitter trait for emitting errors.
-pub trait Emitter {
+pub trait Emitter: Translate {
     /// Emit a structured diagnostic.
     fn emit_diagnostic(&mut self, diag: &Diagnostic);
 
@@ -231,102 +231,6 @@ pub trait Emitter {
 
     fn source_map(&self) -> Option<&Lrc<SourceMap>>;
 
-    /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
-    /// language was requested by the user then this will be `None` and `fallback_fluent_bundle`
-    /// should be used.
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>>;
-
-    /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler.
-    /// Used when the user has not requested a specific language or when a localized diagnostic is
-    /// unavailable for the requested locale.
-    fn fallback_fluent_bundle(&self) -> &FluentBundle;
-
-    /// Convert diagnostic arguments (a rustc internal type that exists to implement
-    /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
-    ///
-    /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
-    /// passed around as a reference thereafter.
-    fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
-        FromIterator::from_iter(args.to_vec().drain(..))
-    }
-
-    /// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
-    fn translate_messages(
-        &self,
-        messages: &[(DiagnosticMessage, Style)],
-        args: &FluentArgs<'_>,
-    ) -> Cow<'_, str> {
-        Cow::Owned(
-            messages.iter().map(|(m, _)| self.translate_message(m, args)).collect::<String>(),
-        )
-    }
-
-    /// Convert a `DiagnosticMessage` to a string, performing translation if necessary.
-    fn translate_message<'a>(
-        &'a self,
-        message: &'a DiagnosticMessage,
-        args: &'a FluentArgs<'_>,
-    ) -> Cow<'_, str> {
-        trace!(?message, ?args);
-        let (identifier, attr) = match message {
-            DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
-            DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
-        };
-
-        let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> {
-            let message = bundle.get_message(&identifier)?;
-            let value = match attr {
-                Some(attr) => message.get_attribute(attr)?.value(),
-                None => message.value()?,
-            };
-            debug!(?message, ?value);
-
-            let mut errs = vec![];
-            let translated = bundle.format_pattern(value, Some(&args), &mut errs);
-            debug!(?translated, ?errs);
-            Some((translated, errs))
-        };
-
-        self.fluent_bundle()
-            .and_then(|bundle| translate_with_bundle(bundle))
-            // If `translate_with_bundle` returns `None` with the primary bundle, this is likely
-            // just that the primary bundle doesn't contain the message being translated, so
-            // proceed to the fallback bundle.
-            //
-            // However, when errors are produced from translation, then that means the translation
-            // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided).
-            //
-            // In debug builds, assert so that compiler devs can spot the broken translation and
-            // fix it..
-            .inspect(|(_, errs)| {
-                debug_assert!(
-                    errs.is_empty(),
-                    "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
-                    identifier,
-                    attr,
-                    args,
-                    errs
-                );
-            })
-            // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
-            // just hide it and try with the fallback bundle.
-            .filter(|(_, errs)| errs.is_empty())
-            .or_else(|| translate_with_bundle(self.fallback_fluent_bundle()))
-            .map(|(translated, errs)| {
-                // Always bail out for errors with the fallback bundle.
-                assert!(
-                    errs.is_empty(),
-                    "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
-                    identifier,
-                    attr,
-                    args,
-                    errs
-                );
-                translated
-            })
-            .expect("failed to find message in primary or fallback fluent bundles")
-    }
-
     /// Formats the substitutions of the primary_span
     ///
     /// There are a lot of conditions to this method, but in short:
@@ -616,11 +520,7 @@ pub trait Emitter {
     }
 }
 
-impl Emitter for EmitterWriter {
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-        self.sm.as_ref()
-    }
-
+impl Translate for EmitterWriter {
     fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
         self.fluent_bundle.as_ref()
     }
@@ -628,6 +528,12 @@ impl Emitter for EmitterWriter {
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
         &**self.fallback_bundle
     }
+}
+
+impl Emitter for EmitterWriter {
+    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+        self.sm.as_ref()
+    }
 
     fn emit_diagnostic(&mut self, diag: &Diagnostic) {
         let fluent_args = self.to_fluent_args(diag.args());
@@ -672,11 +578,7 @@ pub struct SilentEmitter {
     pub fatal_note: Option<String>,
 }
 
-impl Emitter for SilentEmitter {
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-        None
-    }
-
+impl Translate for SilentEmitter {
     fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
         None
     }
@@ -684,6 +586,12 @@ impl Emitter for SilentEmitter {
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
         panic!("silent emitter attempted to translate message")
     }
+}
+
+impl Emitter for SilentEmitter {
+    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+        None
+    }
 
     fn emit_diagnostic(&mut self, d: &Diagnostic) {
         if d.level == Level::Fatal {
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index b8cd334b4c6c6..1680c6accd78c 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -13,6 +13,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
 
 use crate::emitter::{Emitter, HumanReadableErrorType};
 use crate::registry::Registry;
+use crate::translation::Translate;
 use crate::DiagnosticId;
 use crate::{
     CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
@@ -122,6 +123,16 @@ impl JsonEmitter {
     }
 }
 
+impl Translate for JsonEmitter {
+    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
+        self.fluent_bundle.as_ref()
+    }
+
+    fn fallback_fluent_bundle(&self) -> &FluentBundle {
+        &**self.fallback_bundle
+    }
+}
+
 impl Emitter for JsonEmitter {
     fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
         let data = Diagnostic::from_errors_diagnostic(diag, self);
@@ -189,14 +200,6 @@ impl Emitter for JsonEmitter {
         Some(&self.sm)
     }
 
-    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
-        self.fluent_bundle.as_ref()
-    }
-
-    fn fallback_fluent_bundle(&self) -> &FluentBundle {
-        &**self.fallback_bundle
-    }
-
     fn should_show_explain(&self) -> bool {
         !matches!(self.json_rendered, HumanReadableErrorType::Short(_))
     }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 395bf5aad01b6..6555b93ac0b1b 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -58,6 +58,7 @@ mod lock;
 pub mod registry;
 mod snippet;
 mod styled_buffer;
+pub mod translation;
 
 pub use snippet::Style;
 
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
new file mode 100644
index 0000000000000..65338f56d9ccb
--- /dev/null
+++ b/compiler/rustc_errors/src/translation.rs
@@ -0,0 +1,103 @@
+use crate::snippet::Style;
+use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
+use rustc_data_structures::sync::Lrc;
+use rustc_error_messages::FluentArgs;
+use std::borrow::Cow;
+
+pub trait Translate {
+    /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
+    /// language was requested by the user then this will be `None` and `fallback_fluent_bundle`
+    /// should be used.
+    fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>>;
+
+    /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler.
+    /// Used when the user has not requested a specific language or when a localized diagnostic is
+    /// unavailable for the requested locale.
+    fn fallback_fluent_bundle(&self) -> &FluentBundle;
+
+    /// Convert diagnostic arguments (a rustc internal type that exists to implement
+    /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
+    ///
+    /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
+    /// passed around as a reference thereafter.
+    fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
+        FromIterator::from_iter(args.to_vec().drain(..))
+    }
+
+    /// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
+    fn translate_messages(
+        &self,
+        messages: &[(DiagnosticMessage, Style)],
+        args: &FluentArgs<'_>,
+    ) -> Cow<'_, str> {
+        Cow::Owned(
+            messages.iter().map(|(m, _)| self.translate_message(m, args)).collect::<String>(),
+        )
+    }
+
+    /// Convert a `DiagnosticMessage` to a string, performing translation if necessary.
+    fn translate_message<'a>(
+        &'a self,
+        message: &'a DiagnosticMessage,
+        args: &'a FluentArgs<'_>,
+    ) -> Cow<'_, str> {
+        trace!(?message, ?args);
+        let (identifier, attr) = match message {
+            DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
+            DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
+        };
+
+        let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> {
+            let message = bundle.get_message(&identifier)?;
+            let value = match attr {
+                Some(attr) => message.get_attribute(attr)?.value(),
+                None => message.value()?,
+            };
+            debug!(?message, ?value);
+
+            let mut errs = vec![];
+            let translated = bundle.format_pattern(value, Some(&args), &mut errs);
+            debug!(?translated, ?errs);
+            Some((translated, errs))
+        };
+
+        self.fluent_bundle()
+            .and_then(|bundle| translate_with_bundle(bundle))
+            // If `translate_with_bundle` returns `None` with the primary bundle, this is likely
+            // just that the primary bundle doesn't contain the message being translated, so
+            // proceed to the fallback bundle.
+            //
+            // However, when errors are produced from translation, then that means the translation
+            // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided).
+            //
+            // In debug builds, assert so that compiler devs can spot the broken translation and
+            // fix it..
+            .inspect(|(_, errs)| {
+                debug_assert!(
+                    errs.is_empty(),
+                    "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
+                    identifier,
+                    attr,
+                    args,
+                    errs
+                );
+            })
+            // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
+            // just hide it and try with the fallback bundle.
+            .filter(|(_, errs)| errs.is_empty())
+            .or_else(|| translate_with_bundle(self.fallback_fluent_bundle()))
+            .map(|(translated, errs)| {
+                // Always bail out for errors with the fallback bundle.
+                assert!(
+                    errs.is_empty(),
+                    "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}",
+                    identifier,
+                    attr,
+                    args,
+                    errs
+                );
+                translated
+            })
+            .expect("failed to find message in primary or fallback fluent bundles")
+    }
+}
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index fa3e2a4a5b81c..b971a63ec8977 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -3,6 +3,7 @@ use crate::base::ExtCtxt;
 use rustc_ast::attr;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp};
+use rustc_data_structures::sync::Lrc;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 
@@ -330,23 +331,38 @@ impl<'a> ExtCtxt<'a> {
         self.expr_struct(span, self.path_ident(span, id), fields)
     }
 
-    pub fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P<ast::Expr> {
+    fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P<ast::Expr> {
         let lit = ast::Lit::from_lit_kind(lit_kind, span);
         self.expr(span, ast::ExprKind::Lit(lit))
     }
+
     pub fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr> {
         self.expr_lit(
             span,
             ast::LitKind::Int(i as u128, ast::LitIntType::Unsigned(ast::UintTy::Usize)),
         )
     }
+
     pub fn expr_u32(&self, sp: Span, u: u32) -> P<ast::Expr> {
         self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U32)))
     }
+
     pub fn expr_bool(&self, sp: Span, value: bool) -> P<ast::Expr> {
         self.expr_lit(sp, ast::LitKind::Bool(value))
     }
 
+    pub fn expr_str(&self, sp: Span, s: Symbol) -> P<ast::Expr> {
+        self.expr_lit(sp, ast::LitKind::Str(s, ast::StrStyle::Cooked))
+    }
+
+    pub fn expr_char(&self, sp: Span, ch: char) -> P<ast::Expr> {
+        self.expr_lit(sp, ast::LitKind::Char(ch))
+    }
+
+    pub fn expr_byte_str(&self, sp: Span, bytes: Vec<u8>) -> P<ast::Expr> {
+        self.expr_lit(sp, ast::LitKind::ByteStr(Lrc::from(bytes)))
+    }
+
     /// `[expr1, expr2, ...]`
     pub fn expr_array(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::Array(exprs))
@@ -357,10 +373,6 @@ impl<'a> ExtCtxt<'a> {
         self.expr_addr_of(sp, self.expr_array(sp, exprs))
     }
 
-    pub fn expr_str(&self, sp: Span, s: Symbol) -> P<ast::Expr> {
-        self.expr_lit(sp, ast::LitKind::Str(s, ast::StrStyle::Cooked))
-    }
-
     pub fn expr_cast(&self, sp: Span, expr: P<ast::Expr>, ty: P<ast::Ty>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::Cast(expr, ty))
     }
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index fc808401a5eb1..99fe474541e9d 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -112,7 +112,7 @@ fn parse_depth<'sess>(
             "meta-variable expression depth must be a literal"
         ));
     };
-    if let Ok(lit_kind) = LitKind::from_lit_token(*lit)
+    if let Ok(lit_kind) = LitKind::from_token_lit(*lit)
         && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind
         && let Ok(n_usize) = usize::try_from(n_u128)
     {
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 7d9a4aed0bf54..beb33c05913cf 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -486,20 +486,26 @@ impl server::TokenStream for Rustc<'_, '_> {
         // We don't use `TokenStream::from_ast` as the tokenstream currently cannot
         // be recovered in the general case.
         match &expr.kind {
-            ast::ExprKind::Lit(l) if l.token.kind == token::Bool => Ok(
-                tokenstream::TokenStream::token_alone(token::Ident(l.token.symbol, false), l.span),
-            ),
+            ast::ExprKind::Lit(l) if l.token_lit.kind == token::Bool => {
+                Ok(tokenstream::TokenStream::token_alone(
+                    token::Ident(l.token_lit.symbol, false),
+                    l.span,
+                ))
+            }
             ast::ExprKind::Lit(l) => {
-                Ok(tokenstream::TokenStream::token_alone(token::Literal(l.token), l.span))
+                Ok(tokenstream::TokenStream::token_alone(token::Literal(l.token_lit), l.span))
             }
             ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
-                ast::ExprKind::Lit(l) => match l.token {
+                ast::ExprKind::Lit(l) => match l.token_lit {
                     token::Lit { kind: token::Integer | token::Float, .. } => {
                         Ok(Self::TokenStream::from_iter([
                             // FIXME: The span of the `-` token is lost when
                             // parsing, so we cannot faithfully recover it here.
                             tokenstream::TokenTree::token_alone(token::BinOp(token::Minus), e.span),
-                            tokenstream::TokenTree::token_alone(token::Literal(l.token), l.span),
+                            tokenstream::TokenTree::token_alone(
+                                token::Literal(l.token_lit),
+                                l.span,
+                            ),
                         ]))
                     }
                     _ => Err(()),
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index e6fcb84730ea4..0f754dddbec84 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1247,7 +1247,7 @@ impl<'a> State<'a> {
 
     fn print_literal(&mut self, lit: &hir::Lit) {
         self.maybe_print_comment(lit.span.lo());
-        self.word(lit.node.to_lit_token().to_string())
+        self.word(lit.node.to_token_lit().to_string())
     }
 
     fn print_inline_asm(&mut self, asm: &hir::InlineAsm<'_>) {
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 1ecbc876c8d8a..da4002d09ad02 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -17,6 +17,7 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_borrowck = { path = "../rustc_borrowck" }
 rustc_builtin_macros = { path = "../rustc_builtin_macros" }
 rustc_expand = { path = "../rustc_expand" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 8f0835917861a..e00d0b7d0d82f 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -8,11 +8,12 @@ use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::parallel;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
-use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult};
+use rustc_errors::{ErrorGuaranteed, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
 use rustc_hir::def_id::StableCrateId;
 use rustc_hir::definitions::Definitions;
 use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore};
+use rustc_macros::SessionDiagnostic;
 use rustc_metadata::creader::CStore;
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
@@ -30,7 +31,7 @@ use rustc_session::output::filename_for_input;
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::FileName;
+use rustc_span::{FileName, Span};
 use rustc_trait_selection::traits;
 use rustc_typeck as typeck;
 use tracing::{info, warn};
@@ -263,6 +264,23 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> {
     }
 }
 
+#[derive(SessionDiagnostic)]
+#[error(interface::ferris_identifier)]
+struct FerrisIdentifier {
+    #[primary_span]
+    spans: Vec<Span>,
+    #[suggestion(code = "ferris", applicability = "maybe-incorrect")]
+    first_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(interface::emoji_identifier)]
+struct EmojiIdentifier {
+    #[primary_span]
+    spans: Vec<Span>,
+    ident: Symbol,
+}
+
 /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
 /// harness if one is to be provided, injection of a dependency on the
@@ -443,23 +461,9 @@ pub fn configure_and_expand(
             spans.sort();
             if ident == sym::ferris {
                 let first_span = spans[0];
-                sess.diagnostic()
-                    .struct_span_err(
-                        MultiSpan::from(spans),
-                        "Ferris cannot be used as an identifier",
-                    )
-                    .span_suggestion(
-                        first_span,
-                        "try using their name instead",
-                        "ferris",
-                        Applicability::MaybeIncorrect,
-                    )
-                    .emit();
+                sess.emit_err(FerrisIdentifier { spans, first_span });
             } else {
-                sess.diagnostic().span_err(
-                    MultiSpan::from(spans),
-                    &format!("identifiers cannot contain emoji: `{}`", ident),
-                );
+                sess.emit_err(EmojiIdentifier { spans, ident });
             }
         }
     });
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index fe2712525eea5..8f22221324a6e 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -120,8 +120,8 @@ impl EarlyLintPass for HiddenUnicodeCodepoints {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
         // byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString`
         let (text, span, padding) = match &expr.kind {
-            ast::ExprKind::Lit(ast::Lit { token, kind, span }) => {
-                let text = token.symbol;
+            ast::ExprKind::Lit(ast::Lit { token_lit, kind, span }) => {
+                let text = token_lit.symbol;
                 if !contains_text_flow_control_chars(text.as_str()) {
                     return;
                 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index cfc75f673c8f5..8a727d9a1825a 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -770,6 +770,7 @@ rustc_queries! {
         desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
+        cycle_delay_bug
     }
 
     /// Performs lint checking for the module.
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 9d6d632c2e89a..c824566c35ff4 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1750,8 +1750,8 @@ impl<'a> Parser<'a> {
             Some(lit) => match lit.kind {
                 ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
                     style,
-                    symbol: lit.token.symbol,
-                    suffix: lit.token.suffix,
+                    symbol: lit.token_lit.symbol,
+                    suffix: lit.token_lit.suffix,
                     span: lit.span,
                     symbol_unescaped,
                 }),
@@ -1828,7 +1828,7 @@ impl<'a> Parser<'a> {
                 let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None);
                 let symbol = Symbol::intern(&suffixless_lit.to_string());
                 let lit = token::Lit::new(token::Err, symbol, lit.suffix);
-                Some(Lit::from_lit_token(lit, span).unwrap_or_else(|_| unreachable!()))
+                Some(Lit::from_token_lit(lit, span).unwrap_or_else(|_| unreachable!()))
             }
         }
     }
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 5673bb83b15f4..c37ae4f32536b 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -20,6 +20,7 @@ rustc_query_system = { path = "../rustc_query_system" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
 tracing = "0.1"
 
 [features]
diff --git a/compiler/rustc_query_impl/src/values.rs b/compiler/rustc_query_impl/src/values.rs
index 718a2971c403d..0ed48f8d4a051 100644
--- a/compiler/rustc_query_impl/src/values.rs
+++ b/compiler/rustc_query_impl/src/values.rs
@@ -43,3 +43,23 @@ impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> {
         }
     }
 }
+
+impl<'tcx> Value<'tcx> for ty::Binder<'_, ty::FnSig<'_>> {
+    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
+        let err = tcx.ty_error();
+        // FIXME(compiler-errors): It would be nice if we could get the
+        // query key, so we could at least generate a fn signature that
+        // has the right arity.
+        let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+            [].into_iter(),
+            err,
+            false,
+            rustc_hir::Unsafety::Normal,
+            rustc_target::spec::abi::Abi::Rust,
+        ));
+
+        // SAFETY: This is never called when `Self` is not `ty::Binder<'tcx, ty::FnSig<'tcx>>`.
+        // FIXME: Represent the above fact in the trait system somehow.
+        unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
+    }
+}
diff --git a/compiler/rustc_target/src/spec/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/armv4t_none_eabi.rs
index a76ffe808c3b2..797dfe52bd149 100644
--- a/compiler/rustc_target/src/spec/armv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv4t_none_eabi.rs
@@ -38,7 +38,9 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::Ld,
             linker: Some("arm-none-eabi-ld".into()),
             asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],
-            features: "+soft-float,+strict-align".into(),
+            // Force-enable 32-bit atomics, which allows the use of atomic load/store only.
+            // The resulting atomics are ABI incompatible with atomics backed by libatomic.
+            features: "+soft-float,+strict-align,+atomics-32".into(),
             main_needs_argc_argv: false,
             atomic_cas: false,
             has_thumb_interworking: true,
diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
index 7125d141af7f5..bdaaed8b5d0e8 100644
--- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
@@ -47,7 +47,9 @@ pub fn target() -> Target {
             asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],
 
             // minimum extra features, these cannot be disabled via -C
-            features: "+soft-float,+strict-align".into(),
+            // Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
+            // The resulting atomics are ABI incompatible with atomics backed by libatomic.
+            features: "+soft-float,+strict-align,+atomics-32".into(),
 
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 9bb41b900b89a..985600d9ebcc2 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -404,12 +404,12 @@ fn resolve_negative_obligation<'cx, 'tcx>(
 pub fn trait_ref_is_knowable<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
-) -> Option<Conflict> {
+) -> Result<(), Conflict> {
     debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
     if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() {
         // A downstream or cousin crate is allowed to implement some
         // substitution of this trait-ref.
-        return Some(Conflict::Downstream);
+        return Err(Conflict::Downstream);
     }
 
     if trait_ref_is_local_or_fundamental(tcx, trait_ref) {
@@ -418,7 +418,7 @@ pub fn trait_ref_is_knowable<'tcx>(
         // allowed to implement a substitution of this trait ref, which
         // means impls could only come from dependencies of this crate,
         // which we already know about.
-        return None;
+        return Ok(());
     }
 
     // This is a remote non-fundamental trait, so if another crate
@@ -431,10 +431,10 @@ pub fn trait_ref_is_knowable<'tcx>(
     // we are an owner.
     if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() {
         debug!("trait_ref_is_knowable: orphan check passed");
-        None
+        Ok(())
     } else {
         debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned");
-        Some(Conflict::Upstream)
+        Err(Conflict::Upstream)
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 50e9b95a445fd..d67bd6292b434 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -75,7 +75,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
     ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
-        if let Some(conflict) = self.is_knowable(stack) {
+        if let Err(conflict) = self.is_knowable(stack) {
             debug!("coherence stage: not knowable");
             if self.intercrate_ambiguity_causes.is_some() {
                 debug!("evaluate_stack: intercrate_ambiguity_causes is some");
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index c01ac19799106..46b50dd92f1ef 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1265,11 +1265,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         Ok(Some(candidate))
     }
 
-    fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
+    fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
         debug!("is_knowable(intercrate={:?})", self.intercrate);
 
         if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
-            return None;
+            return Ok(());
         }
 
         let obligation = &stack.obligation;
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index c82c819169d3a..5ff62f36b4527 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -561,16 +561,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // We just want to check sizedness, so instead of introducing
                     // placeholder lifetimes with probing, we just replace higher lifetimes
                     // with fresh vars.
-                    let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
+                    let arg_span = args.get(i).map(|a| a.span);
+                    let span = arg_span.unwrap_or(expr.span);
                     let input = self.replace_bound_vars_with_fresh_vars(
                         span,
                         infer::LateBoundRegionConversionTime::FnCall,
                         fn_sig.input(i),
                     );
-                    self.require_type_is_sized_deferred(
-                        input,
+                    self.require_type_is_sized(
+                        self.normalize_associated_types_in(span, input),
                         span,
-                        traits::SizedArgumentType(None),
+                        traits::SizedArgumentType(arg_span),
                     );
                 }
             }
@@ -585,7 +586,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 infer::LateBoundRegionConversionTime::FnCall,
                 fn_sig.output(),
             );
-            self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType);
+            self.require_type_is_sized(
+                self.normalize_associated_types_in(expr.span, output),
+                expr.span,
+                traits::SizedReturnType,
+            );
         }
 
         // We always require that the type provided as the value for
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 3a8093345119f..1d9d04ceec0d7 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -442,17 +442,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn require_type_is_sized_deferred(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        if !ty.references_error() {
-            self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
-        }
-    }
-
     pub fn register_bound(
         &self,
         ty: Ty<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index cd152eb97f1bf..f3115fc5c0232 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -35,11 +35,6 @@ pub struct Inherited<'a, 'tcx> {
 
     pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
 
-    // Some additional `Sized` obligations badly affect type inference.
-    // These obligations are added in a later stage of typeck.
-    pub(super) deferred_sized_obligations:
-        RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
-
     // When we process a call like `c()` where `c` is a closure type,
     // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
     // `FnOnce` closure. In that case, we defer full resolution of the
@@ -117,7 +112,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
             infcx,
             fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
             locals: RefCell::new(Default::default()),
-            deferred_sized_obligations: RefCell::new(Vec::new()),
             deferred_call_resolutions: RefCell::new(Default::default()),
             deferred_cast_checks: RefCell::new(Vec::new()),
             deferred_transmute_checks: RefCell::new(Vec::new()),
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 1b50209ee64cc..dfbef544b1d28 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -467,11 +467,6 @@ fn typeck_with_fallback<'tcx>(
         fcx.resolve_rvalue_scopes(def_id.to_def_id());
         fcx.resolve_generator_interiors(def_id.to_def_id());
 
-        for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
-            let ty = fcx.normalize_ty(span, ty);
-            fcx.require_type_is_sized(ty, span, code);
-        }
-
         fcx.select_all_obligations_or_error();
 
         if !fcx.infcx.is_tainted_by_errors() {
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 6548ad2e514fb..23c46f1a74a31 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -394,7 +394,7 @@ impl f32 {
 
     /// Not a Number (NaN).
     ///
-    /// Note that IEEE-745 doesn't define just a single NaN value;
+    /// Note that IEEE-754 doesn't define just a single NaN value;
     /// a plethora of bit patterns are considered to be NaN.
     /// Furthermore, the standard makes a difference
     /// between a "signaling" and a "quiet" NaN,
@@ -632,7 +632,7 @@ impl f32 {
     }
 
     /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
-    /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
+    /// positive sign bit and positive infinity. Note that IEEE-754 doesn't assign any
     /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
@@ -654,7 +654,7 @@ impl f32 {
     }
 
     /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
-    /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
+    /// negative sign bit and negative infinity. Note that IEEE-754 doesn't assign any
     /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 75c92c2f8834a..b5c8241d2943d 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -393,7 +393,7 @@ impl f64 {
 
     /// Not a Number (NaN).
     ///
-    /// Note that IEEE-745 doesn't define just a single NaN value;
+    /// Note that IEEE-754 doesn't define just a single NaN value;
     /// a plethora of bit patterns are considered to be NaN.
     /// Furthermore, the standard makes a difference
     /// between a "signaling" and a "quiet" NaN,
@@ -624,7 +624,7 @@ impl f64 {
     }
 
     /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
-    /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
+    /// positive sign bit and positive infinity. Note that IEEE-754 doesn't assign any
     /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
@@ -655,7 +655,7 @@ impl f64 {
     }
 
     /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
-    /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
+    /// negative sign bit and negative infinity. Note that IEEE-754 doesn't assign any
     /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
diff --git a/library/unwind/build.rs b/library/unwind/build.rs
index 126e41d1e2015..31af390253b6f 100644
--- a/library/unwind/build.rs
+++ b/library/unwind/build.rs
@@ -2,8 +2,14 @@ use std::env;
 
 fn main() {
     println!("cargo:rerun-if-changed=build.rs");
-    let target = env::var("TARGET").expect("TARGET was not set");
+    println!("cargo:rerun-if-env-changed=CARGO_CFG_MIRI");
+
+    if env::var_os("CARGO_CFG_MIRI").is_some() {
+        // Miri doesn't need the linker flags or a libunwind build.
+        return;
+    }
 
+    let target = env::var("TARGET").expect("TARGET was not set");
     if target.contains("android") {
         let build = cc::Build::new();
 
diff --git a/src/doc/book b/src/doc/book
index 36383b4da21db..42ca0ef484fcc 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit 36383b4da21dbd0a0781473bc8ad7ef0ed1b6751
+Subproject commit 42ca0ef484fcc8437a0682cee23abe4b7c407d52
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
index c55611dd6c58b..6038be9d37d72 160000
--- a/src/doc/edition-guide
+++ b/src/doc/edition-guide
@@ -1 +1 @@
-Subproject commit c55611dd6c58bdeb52423b5c52fd0f3c93615ba8
+Subproject commit 6038be9d37d7251c966b486154af621d1794d7af
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 8d1e4dccf7111..8e6aa3448515a 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 8d1e4dccf71114ff56f328f671f2026d8e6b62a2
+Subproject commit 8e6aa3448515a0654e347b5e2510f1d4bc4d5a64
diff --git a/src/doc/reference b/src/doc/reference
index f3d3953bf3b15..e647eb102890e 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit f3d3953bf3b158d596c96d55ce5366f9f3f972e9
+Subproject commit e647eb102890e8927f488bea12672b079eff8d9d
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index ee342dc91e1ba..03301f8ae55fa 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit ee342dc91e1ba1bb1e1f1318f84bbe3bfac04798
+Subproject commit 03301f8ae55fa6f20f7ea152a517598e6db2cdb7
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
index 04f3cf0bb2f5a..d3daa1f28e169 160000
--- a/src/doc/rustc-dev-guide
+++ b/src/doc/rustc-dev-guide
@@ -1 +1 @@
-Subproject commit 04f3cf0bb2f5a6ee2bfc4b1a6a6cd8c11d1c5531
+Subproject commit d3daa1f28e169087becbc5e2b49ac91ca0405a44
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index 0172ef5700b62..381ac7a5deef1 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -1,7 +1,8 @@
 //! Validates syntax inside Rust code blocks (\`\`\`rust).
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{
-    emitter::Emitter, Applicability, Diagnostic, Handler, LazyFallbackBundle, LintDiagnosticBuilder,
+    emitter::Emitter, translation::Translate, Applicability, Diagnostic, Handler,
+    LazyFallbackBundle, LintDiagnosticBuilder,
 };
 use rustc_parse::parse_stream_from_source_str;
 use rustc_session::parse::ParseSess;
@@ -181,6 +182,16 @@ struct BufferEmitter {
     fallback_bundle: LazyFallbackBundle,
 }
 
+impl Translate for BufferEmitter {
+    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+        None
+    }
+
+    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
+        &**self.fallback_bundle
+    }
+}
+
 impl Emitter for BufferEmitter {
     fn emit_diagnostic(&mut self, diag: &Diagnostic) {
         let mut buffer = self.buffer.borrow_mut();
@@ -194,12 +205,4 @@ impl Emitter for BufferEmitter {
     fn source_map(&self) -> Option<&Lrc<SourceMap>> {
         None
     }
-
-    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
-        None
-    }
-
-    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
-        &**self.fallback_bundle
-    }
 }
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-1.rs b/src/test/incremental/const-generics/hash-tyvid-regression-1.rs
index 5ff7b19d8945e..53358b183cbf5 100644
--- a/src/test/incremental/const-generics/hash-tyvid-regression-1.rs
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-1.rs
@@ -9,7 +9,6 @@ where
     use std::convert::TryFrom;
     <[T; N.get()]>::try_from(())
     //~^ error: the trait bound
-    //~| error: the trait bound
     //~| error: mismatched types
 }
 
diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs
index b0e717d8a86ba..9ff1f60c0d5c7 100644
--- a/src/test/rustdoc-json/nested.rs
+++ b/src/test/rustdoc-json/nested.rs
@@ -4,27 +4,28 @@
 // @is nested.json "$.crate_version" \"1.0.0\"
 // @is - "$.index[*][?(@.name=='nested')].kind" \"module\"
 // @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true
-// @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1
+
+// @set l1_id = - "$.index[*][?(@.name=='l1')].id"
+// @ismany - "$.index[*][?(@.name=='nested')].inner.items[*]" $l1_id
 
 // @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\"
 // @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false
-// @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2
 pub mod l1 {
-
     // @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\"
     // @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false
-    // @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1
     // @set l3_id = - "$.index[*][?(@.name=='l3')].id"
-    // @has - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id
     pub mod l3 {
 
         // @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
         // @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
         // @set l4_id = - "$.index[*][?(@.name=='L4')].id"
-        // @has - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
+        // @ismany - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
         pub struct L4;
     }
     // @is nested.json "$.index[*][?(@.inner.source=='l3::L4')].kind" \"import\"
     // @is - "$.index[*][?(@.inner.source=='l3::L4')].inner.glob" false
+    // @is - "$.index[*][?(@.inner.source=='l3::L4')].inner.id" $l4_id
+    // @set l4_use_id = - "$.index[*][?(@.inner.source=='l3::L4')].id"
     pub use l3::L4;
 }
+// @ismany - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id $l4_use_id
diff --git a/src/test/rustdoc-json/reexport/glob_extern.rs b/src/test/rustdoc-json/reexport/glob_extern.rs
index ba1cfd8a0b577..4fe25904423ed 100644
--- a/src/test/rustdoc-json/reexport/glob_extern.rs
+++ b/src/test/rustdoc-json/reexport/glob_extern.rs
@@ -4,15 +4,20 @@
 #![feature(no_core)]
 
 // @is glob_extern.json "$.index[*][?(@.name=='mod1')].kind" \"module\"
-// @is glob_extern.json "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true"
+// @is - "$.index[*][?(@.name=='mod1')].inner.is_stripped" "true"
 mod mod1 {
     extern "C" {
-        // @has - "$.index[*][?(@.name=='public_fn')].id"
+        // @set public_fn_id = - "$.index[*][?(@.name=='public_fn')].id"
         pub fn public_fn();
         // @!has - "$.index[*][?(@.name=='private_fn')]"
         fn private_fn();
     }
+    // @ismany - "$.index[*][?(@.name=='mod1')].inner.items[*]" $public_fn_id
+    // @set mod1_id = - "$.index[*][?(@.name=='mod1')].id"
 }
 
 // @is - "$.index[*][?(@.kind=='import')].inner.glob" true
+// @is - "$.index[*][?(@.kind=='import')].inner.id" $mod1_id
+// @set use_id = - "$.index[*][?(@.kind=='import')].id"
+// @ismany - "$.index[*][?(@.name=='glob_extern')].inner.items[*]" $use_id
 pub use mod1::*;
diff --git a/src/test/rustdoc-json/reexport/glob_private.rs b/src/test/rustdoc-json/reexport/glob_private.rs
index e6a44748c25fb..04460a817f130 100644
--- a/src/test/rustdoc-json/reexport/glob_private.rs
+++ b/src/test/rustdoc-json/reexport/glob_private.rs
@@ -16,7 +16,7 @@ mod mod1 {
         struct Mod2Private;
     }
 
-    // @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod2')]"
+    // @set mod2_use_id = - "$.index[*][?(@.kind=='import' && @.inner.name=='mod2')].id"
     pub use self::mod2::*;
 
     // @set m1pub_id = - "$.index[*][?(@.name=='Mod1Public')].id"
@@ -25,8 +25,9 @@ mod mod1 {
     struct Mod1Private;
 }
 
-// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='mod1')]"
+// @set mod1_use_id = - "$.index[*][?(@.kind=='import' && @.inner.name=='mod1')].id"
 pub use mod1::*;
 
-// @has - "$.index[*][?(@.name=='mod2')].inner.items[*]" $m2pub_id
-// @has - "$.index[*][?(@.name=='mod1')].inner.items[*]" $m1pub_id
+// @ismany - "$.index[*][?(@.name=='mod2')].inner.items[*]" $m2pub_id
+// @ismany - "$.index[*][?(@.name=='mod1')].inner.items[*]" $m1pub_id $mod2_use_id
+// @ismany - "$.index[*][?(@.name=='glob_private')].inner.items[*]" $mod1_use_id
diff --git a/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs b/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs
index 2daadf7620ca0..09302ee3acb2d 100644
--- a/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs
+++ b/src/test/rustdoc-json/reexport/in_root_and_mod_pub.rs
@@ -3,7 +3,7 @@
 
 pub mod foo {
     // @set bar_id = in_root_and_mod_pub.json "$.index[*][?(@.name=='Bar')].id"
-    // @has - "$.index[*][?(@.name=='foo')].inner.items[*]" $bar_id
+    // @ismany - "$.index[*][?(@.name=='foo')].inner.items[*]" $bar_id
     pub struct Bar;
 }
 
@@ -15,6 +15,6 @@ pub use foo::Bar;
 pub mod baz {
     // @set baz_import_id = - "$.index[*][?(@.inner.source=='crate::foo::Bar')].id"
     // @is - "$.index[*][?(@.inner.source=='crate::foo::Bar')].inner.id" $bar_id
-    // @has - "$.index[*][?(@.name=='baz')].inner.items[*]" $baz_import_id
+    // @ismany - "$.index[*][?(@.name=='baz')].inner.items[*]" $baz_import_id
     pub use crate::foo::Bar;
 }
diff --git a/src/test/rustdoc-json/reexport/macro.rs b/src/test/rustdoc-json/reexport/macro.rs
index b86614ffbad68..0959736f30988 100644
--- a/src/test/rustdoc-json/reexport/macro.rs
+++ b/src/test/rustdoc-json/reexport/macro.rs
@@ -3,15 +3,13 @@
 #![no_core]
 #![feature(no_core)]
 
-// @count macro.json "$.index[*][?(@.name=='macro')].inner.items[*]" 2
-
 // @set repro_id = macro.json "$.index[*][?(@.name=='repro')].id"
-// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id
 #[macro_export]
 macro_rules! repro {
     () => {};
 }
 
 // @set repro2_id = macro.json "$.index[*][?(@.inner.name=='repro2')].id"
-// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro2_id
 pub use crate::repro as repro2;
+
+// @ismany macro.json "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id $repro2_id
diff --git a/src/test/rustdoc-json/reexport/private_twice_one_inline.rs b/src/test/rustdoc-json/reexport/private_twice_one_inline.rs
index 327b0f45fdd54..a76d352b28ba4 100644
--- a/src/test/rustdoc-json/reexport/private_twice_one_inline.rs
+++ b/src/test/rustdoc-json/reexport/private_twice_one_inline.rs
@@ -1,18 +1,28 @@
 // aux-build:pub-struct.rs
+// ignore-tidy-linelength
 
-// Test for the ICE in rust/83057
-// Am external type re-exported with different attributes shouldn't cause an error
+// Test for the ICE in https://github.com/rust-lang/rust/issues/83057
+// An external type re-exported with different attributes shouldn't cause an error
 
 #![no_core]
 #![feature(no_core)]
 
 extern crate pub_struct as foo;
-
 #[doc(inline)]
+
+// @set crate_use_id = private_twice_one_inline.json "$.index[*][?(@.docs=='Hack A')].id"
+// @set foo_id = - "$.index[*][?(@.docs=='Hack A')].inner.id"
+/// Hack A
 pub use foo::Foo;
 
+// @set bar_id = - "$.index[*][?(@.name=='bar')].id"
 pub mod bar {
+    // @is - "$.index[*][?(@.docs=='Hack B')].inner.id" $foo_id
+    // @set bar_use_id = - "$.index[*][?(@.docs=='Hack B')].id"
+    // @ismany - "$.index[*][?(@.name=='bar')].inner.items[*]" $bar_use_id
+    /// Hack B
     pub use foo::Foo;
 }
 
-// @count private_twice_one_inline.json "$.index[*][?(@.kind=='import')]" 2
+// @ismany - "$.index[*][?(@.kind=='import')].id" $crate_use_id $bar_use_id
+// @ismany - "$.index[*][?(@.name=='private_twice_one_inline')].inner.items[*]" $bar_id $crate_use_id
diff --git a/src/test/rustdoc-json/reexport/private_two_names.rs b/src/test/rustdoc-json/reexport/private_two_names.rs
index 36d6a50d385a2..cd8212cf34419 100644
--- a/src/test/rustdoc-json/reexport/private_two_names.rs
+++ b/src/test/rustdoc-json/reexport/private_two_names.rs
@@ -1,4 +1,6 @@
-// Test for the ICE in rust/83720
+// ignore-tidy-linelength
+
+// Test for the ICE in https://github.com/rust-lang/rust/issues/83720
 // A pub-in-private type re-exported under two different names shouldn't cause an error
 
 #![no_core]
@@ -7,11 +9,15 @@
 // @is private_two_names.json "$.index[*][?(@.name=='style')].kind" \"module\"
 // @is private_two_names.json "$.index[*][?(@.name=='style')].inner.is_stripped" "true"
 mod style {
-    // @has - "$.index[*](?(@.name=='Color'))"
+    // @set color_struct_id = - "$.index[*][?(@.kind=='struct' && @.name=='Color')].id"
     pub struct Color;
 }
 
-// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')]"
+// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')].inner.id" $color_struct_id
+// @set color_export_id = - "$.index[*][?(@.kind=='import' && @.inner.name=='Color')].id"
 pub use style::Color;
-// @has - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')]"
+// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')].inner.id" $color_struct_id
+// @set colour_export_id = - "$.index[*][?(@.kind=='import' && @.inner.name=='Colour')].id"
 pub use style::Color as Colour;
+
+// @ismany - "$.index[*][?(@.name=='private_two_names')].inner.items[*]" $color_export_id $colour_export_id
diff --git a/src/test/rustdoc-json/reexport/rename_public.rs b/src/test/rustdoc-json/reexport/rename_public.rs
index 2dd438d223058..d41556974b43b 100644
--- a/src/test/rustdoc-json/reexport/rename_public.rs
+++ b/src/test/rustdoc-json/reexport/rename_public.rs
@@ -4,14 +4,14 @@
 #![feature(no_core)]
 
 // @set inner_id = rename_public.json "$.index[*][?(@.name=='inner')].id"
-// @has - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $inner_id
 pub mod inner {
     // @set public_id = - "$.index[*][?(@.name=='Public')].id"
-    // @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
+    // @ismany - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
     pub struct Public;
 }
 // @set import_id = - "$.index[*][?(@.inner.name=='NewName')].id"
 // @!has - "$.index[*][?(@.inner.name=='Public')]"
-// @has - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $import_id
 // @is - "$.index[*][?(@.inner.name=='NewName')].inner.source" \"inner::Public\"
 pub use inner::Public as NewName;
+
+// @ismany - "$.index[*][?(@.name=='rename_public')].inner.items[*]" $inner_id $import_id
diff --git a/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs
index eedddd6a7bb48..1d76c7e139bdb 100644
--- a/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs
+++ b/src/test/rustdoc-json/reexport/same_type_reexported_more_than_once.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-linelength
+
 // Regression test for <https://github.com/rust-lang/rust/issues/97432>.
 
 #![feature(no_core)]
@@ -5,11 +7,17 @@
 #![no_core]
 
 // @has same_type_reexported_more_than_once.json
-// @has - "$.index[*][?(@.name=='Trait')]"
-pub use inner::Trait;
-// @has - "$.index[*].inner[?(@.name=='Reexport')].id"
-pub use inner::Trait as Reexport;
 
 mod inner {
+    // @set trait_id = - "$.index[*][?(@.name=='Trait')].id"
     pub trait Trait {}
 }
+
+// @set export_id = - "$.index[*][?(@.inner.name=='Trait')].id"
+// @is - "$.index[*][?(@.inner.name=='Trait')].inner.id" $trait_id
+pub use inner::Trait;
+// @set reexport_id = - "$.index[*][?(@.inner.name=='Reexport')].id"
+// @is - "$.index[*][?(@.inner.name=='Reexport')].inner.id" $trait_id
+pub use inner::Trait as Reexport;
+
+// @ismany - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $reexport_id $export_id
diff --git a/src/test/rustdoc-json/reexport/simple_private.rs b/src/test/rustdoc-json/reexport/simple_private.rs
index 5ec13e403aef6..55523bcd1deef 100644
--- a/src/test/rustdoc-json/reexport/simple_private.rs
+++ b/src/test/rustdoc-json/reexport/simple_private.rs
@@ -10,6 +10,8 @@ mod inner {
 }
 
 // @is - "$.index[*][?(@.kind=='import')].inner.name" \"Public\"
+// @set use_id = - "$.index[*][?(@.kind=='import')].id"
 pub use inner::Public;
 
-// @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $pub_id
+// @ismany - "$.index[*][?(@.name=='inner')].inner.items[*]" $pub_id
+// @ismany - "$.index[*][?(@.name=='simple_private')].inner.items[*]" $use_id
diff --git a/src/test/rustdoc-json/reexport/simple_public.rs b/src/test/rustdoc-json/reexport/simple_public.rs
index 2e4de301f6f11..a3156a2b33a8e 100644
--- a/src/test/rustdoc-json/reexport/simple_public.rs
+++ b/src/test/rustdoc-json/reexport/simple_public.rs
@@ -4,15 +4,15 @@
 #![feature(no_core)]
 
 // @set inner_id = simple_public.json "$.index[*][?(@.name=='inner')].id"
-// @has - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $inner_id
 pub mod inner {
 
     // @set public_id = - "$.index[*][?(@.name=='Public')].id"
-    // @has - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
+    // @ismany - "$.index[*][?(@.name=='inner')].inner.items[*]" $public_id
     pub struct Public;
 }
 
 // @set import_id = - "$.index[*][?(@.inner.name=='Public')].id"
-// @has - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $import_id
 // @is - "$.index[*][?(@.inner.name=='Public')].inner.source" \"inner::Public\"
 pub use inner::Public;
+
+// @ismany - "$.index[*][?(@.name=='simple_public')].inner.items[*]" $import_id $inner_id
diff --git a/src/test/rustdoc-json/type/fn_lifetime.rs b/src/test/rustdoc-json/type/fn_lifetime.rs
index e0d1e9649a0aa..fd49a0890c0df 100644
--- a/src/test/rustdoc-json/type/fn_lifetime.rs
+++ b/src/test/rustdoc-json/type/fn_lifetime.rs
@@ -2,8 +2,7 @@
 
 // @is fn_lifetime.json "$.index[*][?(@.name=='GenericFn')].kind" \"typedef\"
 
-// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*]" 1
-// @is    - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\"
+// @ismany    - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\"
 // @has   - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime"
 // @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime.outlives[*]" 0
 // @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.where_predicates[*]" 0
diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr
index c37d469890c08..66f1ab726922d 100644
--- a/src/test/ui/associated-types/associated-types-path-2.stderr
+++ b/src/test/ui/associated-types/associated-types-path-2.stderr
@@ -33,7 +33,9 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
   --> $DIR/associated-types-path-2.rs:29:14
    |
 LL |     f1(2u32, 4u32);
-   |              ^^^^ the trait `Foo` is not implemented for `u32`
+   |     --       ^^^^ the trait `Foo` is not implemented for `u32`
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Foo` is implemented for `i32`
 
diff --git a/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr
index 0f7520ef7f8a9..0557340f792fd 100644
--- a/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr
@@ -15,11 +15,16 @@ error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known
   --> $DIR/feature-gate-unsized_fn_params.rs:24:9
    |
 LL |     foo(*x);
-   |         ^^ doesn't have a size known at compile-time
+   |     --- ^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
-   = note: all function arguments must have a statically known size
    = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     foo(&*x);
+   |         +
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/iterators/issue-28098.rs b/src/test/ui/iterators/issue-28098.rs
index 62a90d90d12de..c4addaccefc10 100644
--- a/src/test/ui/iterators/issue-28098.rs
+++ b/src/test/ui/iterators/issue-28098.rs
@@ -1,7 +1,6 @@
 fn main() {
     let _ = Iterator::next(&mut ());
     //~^ ERROR `()` is not an iterator
-    //~| ERROR `()` is not an iterator
 
     for _ in false {}
     //~^ ERROR `bool` is not an iterator
@@ -17,7 +16,6 @@ pub fn other() {
 
     let _ = Iterator::next(&mut ());
     //~^ ERROR `()` is not an iterator
-    //~| ERROR `()` is not an iterator
 
     let _ = Iterator::next(&mut ());
     //~^ ERROR `()` is not an iterator
diff --git a/src/test/ui/iterators/issue-28098.stderr b/src/test/ui/iterators/issue-28098.stderr
index 3beb9929244bf..e7128248f9341 100644
--- a/src/test/ui/iterators/issue-28098.stderr
+++ b/src/test/ui/iterators/issue-28098.stderr
@@ -9,7 +9,7 @@ LL |     let _ = Iterator::next(&mut ());
    = help: the trait `Iterator` is not implemented for `()`
 
 error[E0277]: `bool` is not an iterator
-  --> $DIR/issue-28098.rs:6:14
+  --> $DIR/issue-28098.rs:5:14
    |
 LL |     for _ in false {}
    |              ^^^^^ `bool` is not an iterator
@@ -18,7 +18,7 @@ LL |     for _ in false {}
    = note: required because of the requirements on the impl of `IntoIterator` for `bool`
 
 error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:9:28
+  --> $DIR/issue-28098.rs:8:28
    |
 LL |     let _ = Iterator::next(&mut ());
    |             -------------- ^^^^^^^ `()` is not an iterator
@@ -28,15 +28,7 @@ LL |     let _ = Iterator::next(&mut ());
    = help: the trait `Iterator` is not implemented for `()`
 
 error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:2:13
-   |
-LL |     let _ = Iterator::next(&mut ());
-   |             ^^^^^^^^^^^^^^ `()` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:18:28
+  --> $DIR/issue-28098.rs:17:28
    |
 LL |     let _ = Iterator::next(&mut ());
    |             -------------- ^^^^^^^ `()` is not an iterator
@@ -46,7 +38,7 @@ LL |     let _ = Iterator::next(&mut ());
    = help: the trait `Iterator` is not implemented for `()`
 
 error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:22:28
+  --> $DIR/issue-28098.rs:20:28
    |
 LL |     let _ = Iterator::next(&mut ());
    |             -------------- ^^^^^^^ `()` is not an iterator
@@ -56,7 +48,7 @@ LL |     let _ = Iterator::next(&mut ());
    = help: the trait `Iterator` is not implemented for `()`
 
 error[E0277]: `bool` is not an iterator
-  --> $DIR/issue-28098.rs:25:14
+  --> $DIR/issue-28098.rs:23:14
    |
 LL |     for _ in false {}
    |              ^^^^^ `bool` is not an iterator
@@ -64,14 +56,6 @@ LL |     for _ in false {}
    = help: the trait `Iterator` is not implemented for `bool`
    = note: required because of the requirements on the impl of `IntoIterator` for `bool`
 
-error[E0277]: `()` is not an iterator
-  --> $DIR/issue-28098.rs:18:13
-   |
-LL |     let _ = Iterator::next(&mut ());
-   |             ^^^^^^^^^^^^^^ `()` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `()`
-
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/on-unimplemented/multiple-impls.rs b/src/test/ui/on-unimplemented/multiple-impls.rs
index b74957ebcd406..79c40f650db81 100644
--- a/src/test/ui/on-unimplemented/multiple-impls.rs
+++ b/src/test/ui/on-unimplemented/multiple-impls.rs
@@ -32,11 +32,8 @@ impl Index<Bar<usize>> for [i32] {
 fn main() {
     Index::index(&[] as &[i32], 2u32);
     //~^ ERROR E0277
-    //~| ERROR E0277
     Index::index(&[] as &[i32], Foo(2u32));
     //~^ ERROR E0277
-    //~| ERROR E0277
     Index::index(&[] as &[i32], Bar(2u32));
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
diff --git a/src/test/ui/on-unimplemented/multiple-impls.stderr b/src/test/ui/on-unimplemented/multiple-impls.stderr
index 06e1a222af881..6e3601d7bf4b5 100644
--- a/src/test/ui/on-unimplemented/multiple-impls.stderr
+++ b/src/test/ui/on-unimplemented/multiple-impls.stderr
@@ -12,7 +12,7 @@ LL |     Index::index(&[] as &[i32], 2u32);
              <[i32] as Index<Foo<usize>>>
 
 error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
-  --> $DIR/multiple-impls.rs:36:18
+  --> $DIR/multiple-impls.rs:35:18
    |
 LL |     Index::index(&[] as &[i32], Foo(2u32));
    |     ------------ ^^^^^^^^^^^^^ on impl for Foo
@@ -25,7 +25,7 @@ LL |     Index::index(&[] as &[i32], Foo(2u32));
              <[i32] as Index<Foo<usize>>>
 
 error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
-  --> $DIR/multiple-impls.rs:39:18
+  --> $DIR/multiple-impls.rs:37:18
    |
 LL |     Index::index(&[] as &[i32], Bar(2u32));
    |     ------------ ^^^^^^^^^^^^^ on impl for Bar
@@ -37,39 +37,6 @@ LL |     Index::index(&[] as &[i32], Bar(2u32));
              <[i32] as Index<Bar<usize>>>
              <[i32] as Index<Foo<usize>>>
 
-error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
-  --> $DIR/multiple-impls.rs:33:5
-   |
-LL |     Index::index(&[] as &[i32], 2u32);
-   |     ^^^^^^^^^^^^ trait message
-   |
-   = help: the trait `Index<u32>` is not implemented for `[i32]`
-   = help: the following other types implement trait `Index<Idx>`:
-             <[i32] as Index<Bar<usize>>>
-             <[i32] as Index<Foo<usize>>>
-
-error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
-  --> $DIR/multiple-impls.rs:36:5
-   |
-LL |     Index::index(&[] as &[i32], Foo(2u32));
-   |     ^^^^^^^^^^^^ on impl for Foo
-   |
-   = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
-   = help: the following other types implement trait `Index<Idx>`:
-             <[i32] as Index<Bar<usize>>>
-             <[i32] as Index<Foo<usize>>>
-
-error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
-  --> $DIR/multiple-impls.rs:39:5
-   |
-LL |     Index::index(&[] as &[i32], Bar(2u32));
-   |     ^^^^^^^^^^^^ on impl for Bar
-   |
-   = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
-   = help: the following other types implement trait `Index<Idx>`:
-             <[i32] as Index<Bar<usize>>>
-             <[i32] as Index<Foo<usize>>>
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/on-unimplemented/on-impl.rs b/src/test/ui/on-unimplemented/on-impl.rs
index ab3e67d01fe44..b03e1f7c6a8df 100644
--- a/src/test/ui/on-unimplemented/on-impl.rs
+++ b/src/test/ui/on-unimplemented/on-impl.rs
@@ -21,5 +21,4 @@ impl Index<usize> for [i32] {
 fn main() {
     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
diff --git a/src/test/ui/on-unimplemented/on-impl.stderr b/src/test/ui/on-unimplemented/on-impl.stderr
index 769a3d77a5726..396c062cfe2ac 100644
--- a/src/test/ui/on-unimplemented/on-impl.stderr
+++ b/src/test/ui/on-unimplemented/on-impl.stderr
@@ -9,15 +9,6 @@ LL |     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
    = help: the trait `Index<u32>` is not implemented for `[i32]`
    = help: the trait `Index<usize>` is implemented for `[i32]`
 
-error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
-  --> $DIR/on-impl.rs:22:5
-   |
-LL |     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
-   |     ^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice
-   |
-   = help: the trait `Index<u32>` is not implemented for `[i32]`
-   = help: the trait `Index<usize>` is implemented for `[i32]`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/return-cycle-2.rs b/src/test/ui/suggestions/return-cycle-2.rs
new file mode 100644
index 0000000000000..d6d24be1b8dc4
--- /dev/null
+++ b/src/test/ui/suggestions/return-cycle-2.rs
@@ -0,0 +1,14 @@
+use std::marker::PhantomData;
+
+struct Token<T>(PhantomData<T>);
+
+impl<T> Token<T> {
+    fn as_ref(_: i32, _: i32) -> _ {
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+        //~| NOTE not allowed in type signatures
+        //~| HELP replace with the correct return type
+        Token(PhantomData::<&T>)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/return-cycle-2.stderr b/src/test/ui/suggestions/return-cycle-2.stderr
new file mode 100644
index 0000000000000..3a1a0f7f4f543
--- /dev/null
+++ b/src/test/ui/suggestions/return-cycle-2.stderr
@@ -0,0 +1,12 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/return-cycle-2.rs:6:34
+   |
+LL |     fn as_ref(_: i32, _: i32) -> _ {
+   |                                  ^
+   |                                  |
+   |                                  not allowed in type signatures
+   |                                  help: replace with the correct return type: `Token<&'static T>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/suggestions/return-cycle.rs b/src/test/ui/suggestions/return-cycle.rs
new file mode 100644
index 0000000000000..60b80e35a20b8
--- /dev/null
+++ b/src/test/ui/suggestions/return-cycle.rs
@@ -0,0 +1,14 @@
+use std::marker::PhantomData;
+
+struct Token<T>(PhantomData<T>);
+
+impl<T> Token<T> {
+    fn new() -> _ {
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+        //~| NOTE not allowed in type signatures
+        //~| HELP replace with the correct return type
+        Token(PhantomData::<()>)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/return-cycle.stderr b/src/test/ui/suggestions/return-cycle.stderr
new file mode 100644
index 0000000000000..63fa9e040874d
--- /dev/null
+++ b/src/test/ui/suggestions/return-cycle.stderr
@@ -0,0 +1,12 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/return-cycle.rs:6:17
+   |
+LL |     fn new() -> _ {
+   |                 ^
+   |                 |
+   |                 not allowed in type signatures
+   |                 help: replace with the correct return type: `Token<()>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/unsized/issue-30355.stderr b/src/test/ui/unsized/issue-30355.stderr
index 71bbdf5dec769..d7af558eef42a 100644
--- a/src/test/ui/unsized/issue-30355.stderr
+++ b/src/test/ui/unsized/issue-30355.stderr
@@ -2,11 +2,16 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
   --> $DIR/issue-30355.rs:5:8
    |
 LL |     &X(*Y)
-   |        ^^ doesn't have a size known at compile-time
+   |      - ^^ doesn't have a size known at compile-time
+   |      |
+   |      required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `[u8]`
-   = note: all function arguments must have a statically known size
    = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     &X(&*Y)
+   |        +
 
 error: aborting due to previous error
 
diff --git a/src/tools/cargo b/src/tools/cargo
index efd4ca3dc0b89..9809f8ff33c2b 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit efd4ca3dc0b89929dc8c5f5c023d25978d76cb61
+Subproject commit 9809f8ff33c2b998919fd0432c626f0f7323697a
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index 6ad6837f0e350..bffbf20b4d289 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -57,10 +57,10 @@ impl EarlyLintPass for OctalEscapes {
         }
 
         if let ExprKind::Lit(lit) = &expr.kind {
-            if matches!(lit.token.kind, LitKind::Str) {
-                check_lit(cx, &lit.token, lit.span, true);
-            } else if matches!(lit.token.kind, LitKind::ByteStr) {
-                check_lit(cx, &lit.token, lit.span, false);
+            if matches!(lit.token_lit.kind, LitKind::Str) {
+                check_lit(cx, &lit.token_lit, lit.span, true);
+            } else if matches!(lit.token_lit.kind, LitKind::ByteStr) {
+                check_lit(cx, &lit.token_lit, lit.span, false);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 32718200c0b3a..fa2383066f3f6 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -589,12 +589,12 @@ impl Write {
                 },
             };
 
-            let replacement: String = match lit.token.kind {
+            let replacement: String = match lit.token_lit.kind {
                 LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => {
-                    lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}")
+                    lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}")
                 },
                 LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => {
-                    lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}")
+                    lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}")
                 },
                 LitKind::StrRaw(_)
                 | LitKind::Str
@@ -603,7 +603,7 @@ impl Write {
                 | LitKind::Integer
                 | LitKind::Float
                 | LitKind::Err => continue,
-                LitKind::Byte | LitKind::Char => match lit.token.symbol.as_str() {
+                LitKind::Byte | LitKind::Char => match lit.token_lit.symbol.as_str() {
                     "\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"",
                     "\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue,
                     "\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\",
@@ -614,7 +614,7 @@ impl Write {
                     x => x,
                 }
                 .into(),
-                LitKind::Bool => lit.token.symbol.as_str().deref().into(),
+                LitKind::Bool => lit.token_lit.symbol.as_str().deref().into(),
             };
 
             if !fmt_spans.is_empty() {
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index c44624666465e..022f7eb8e02d0 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -50,6 +50,7 @@ pub enum CommandKind {
     Has,
     Count,
     Is,
+    IsMany,
     Set,
 }
 
@@ -57,6 +58,7 @@ impl CommandKind {
     fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
         let count = match self {
             CommandKind::Has => (1..=3).contains(&args.len()),
+            CommandKind::IsMany => args.len() >= 3,
             CommandKind::Count | CommandKind::Is => 3 == args.len(),
             CommandKind::Set => 4 == args.len(),
         };
@@ -89,6 +91,7 @@ impl fmt::Display for CommandKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let text = match self {
             CommandKind::Has => "has",
+            CommandKind::IsMany => "ismany",
             CommandKind::Count => "count",
             CommandKind::Is => "is",
             CommandKind::Set => "set",
@@ -137,6 +140,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
             "has" => CommandKind::Has,
             "count" => CommandKind::Count,
             "is" => CommandKind::Is,
+            "ismany" => CommandKind::IsMany,
             "set" => CommandKind::Set,
             _ => {
                 print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
@@ -227,6 +231,44 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
                 _ => unreachable!(),
             }
         }
+        CommandKind::IsMany => {
+            // @ismany <path> <jsonpath> <value>...
+            let (path, query, values) = if let [path, query, values @ ..] = &command.args[..] {
+                (path, query, values)
+            } else {
+                unreachable!("Checked in CommandKind::validate")
+            };
+            let val = cache.get_value(path)?;
+            let got_values = select(&val, &query).unwrap();
+            assert!(!command.negated, "`@!ismany` is not supported");
+
+            // Serde json doesn't implement Ord or Hash for Value, so we must
+            // use a Vec here. While in theory that makes setwize equality
+            // O(n^2), in practice n will never be large enought to matter.
+            let expected_values =
+                values.iter().map(|v| string_to_value(v, cache)).collect::<Vec<_>>();
+            if expected_values.len() != got_values.len() {
+                return Err(CkError::FailedCheck(
+                    format!(
+                        "Expected {} values, but `{}` matched to {} values ({:?})",
+                        expected_values.len(),
+                        query,
+                        got_values.len(),
+                        got_values
+                    ),
+                    command,
+                ));
+            };
+            for got_value in got_values {
+                if !expected_values.iter().any(|exp| &**exp == got_value) {
+                    return Err(CkError::FailedCheck(
+                        format!("`{}` has match {:?}, which was not expected", query, got_value),
+                        command,
+                    ));
+                }
+            }
+            true
+        }
         CommandKind::Count => {
             // @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
             assert_eq!(command.args.len(), 3);
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index a7b73ba78c59e..3105882e2d308 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -79,7 +79,7 @@ pub(crate) fn format_expr(
             if let Some(expr_rw) = rewrite_literal(context, l, shape) {
                 Some(expr_rw)
             } else {
-                if let LitKind::StrRaw(_) = l.token.kind {
+                if let LitKind::StrRaw(_) = l.token_lit.kind {
                     Some(context.snippet(l.span).trim().into())
                 } else {
                     None
@@ -1226,7 +1226,7 @@ fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) ->
 
 fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -> Option<String> {
     let span = lit.span;
-    let symbol = lit.token.symbol.as_str();
+    let symbol = lit.token_lit.symbol.as_str();
 
     if let Some(symbol_stripped) = symbol.strip_prefix("0x") {
         let hex_lit = match context.config.hex_literal_case() {
@@ -1239,7 +1239,9 @@ fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -
                 format!(
                     "0x{}{}",
                     hex_lit,
-                    lit.token.suffix.map_or(String::new(), |s| s.to_string())
+                    lit.token_lit
+                        .suffix
+                        .map_or(String::new(), |s| s.to_string())
                 ),
                 context.config.max_width(),
                 shape,
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 23db542191036..6efeee98fea6c 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -3,6 +3,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
 
 use rustc_data_structures::sync::{Lrc, Send};
 use rustc_errors::emitter::{Emitter, EmitterWriter};
+use rustc_errors::translation::Translate;
 use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel};
 use rustc_session::parse::ParseSess as RawParseSess;
 use rustc_span::{
@@ -28,19 +29,24 @@ pub(crate) struct ParseSess {
 /// Emitter which discards every error.
 struct SilentEmitter;
 
-impl Emitter for SilentEmitter {
-    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
-        None
-    }
-    fn emit_diagnostic(&mut self, _db: &Diagnostic) {}
+impl Translate for SilentEmitter {
     fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
         None
     }
+
     fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
         panic!("silent emitter attempted to translate a diagnostic");
     }
 }
 
+impl Emitter for SilentEmitter {
+    fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+        None
+    }
+
+    fn emit_diagnostic(&mut self, _db: &Diagnostic) {}
+}
+
 fn silent_emitter() -> Box<dyn Emitter + Send> {
     Box::new(SilentEmitter {})
 }
@@ -62,10 +68,21 @@ impl SilentOnIgnoredFilesEmitter {
     }
 }
 
+impl Translate for SilentOnIgnoredFilesEmitter {
+    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+        self.emitter.fluent_bundle()
+    }
+
+    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
+        self.emitter.fallback_fluent_bundle()
+    }
+}
+
 impl Emitter for SilentOnIgnoredFilesEmitter {
     fn source_map(&self) -> Option<&Lrc<SourceMap>> {
         None
     }
+
     fn emit_diagnostic(&mut self, db: &Diagnostic) {
         if db.level() == DiagnosticLevel::Fatal {
             return self.handle_non_ignoreable_error(db);
@@ -88,14 +105,6 @@ impl Emitter for SilentOnIgnoredFilesEmitter {
         }
         self.handle_non_ignoreable_error(db);
     }
-
-    fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
-        self.emitter.fluent_bundle()
-    }
-
-    fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
-        self.emitter.fallback_fluent_bundle()
-    }
 }
 
 fn default_handler(
@@ -340,19 +349,24 @@ mod tests {
             num_emitted_errors: Lrc<AtomicU32>,
         }
 
+        impl Translate for TestEmitter {
+            fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
+                None
+            }
+
+            fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
+                panic!("test emitter attempted to translate a diagnostic");
+            }
+        }
+
         impl Emitter for TestEmitter {
             fn source_map(&self) -> Option<&Lrc<SourceMap>> {
                 None
             }
+
             fn emit_diagnostic(&mut self, _db: &Diagnostic) {
                 self.num_emitted_errors.fetch_add(1, Ordering::Release);
             }
-            fn fluent_bundle(&self) -> Option<&Lrc<rustc_errors::FluentBundle>> {
-                None
-            }
-            fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
-                panic!("test emitter attempted to translate a diagnostic");
-            }
         }
 
         fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> Diagnostic {
diff --git a/triagebot.toml b/triagebot.toml
index ea654192bbf78..b7532e016b68e 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -178,6 +178,13 @@ trigger_files = [
     "src/tools/bump-stage0",
 ]
 
+[autolabel."A-translation"]
+trigger_files = [
+    "compiler/rustc_error_messages",
+    "compiler/rustc_errors/src/translation.rs",
+    "compiler/rustc_macros/src/diagnostics"
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"
@@ -342,3 +349,15 @@ cc = ["@rust-lang/rustfmt"]
 [mentions."compiler/rustc_middle/src/mir/syntax.rs"]
 message = "This PR changes MIR"
 cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@celinval", "@vakaras"]
+
+[mentions."compiler/rustc_error_messages"]
+message = "`rustc_error_messages` was changed"
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]
+
+[mentions."compiler/rustc_errors/src/translation.rs"]
+message = "`rustc_errors::translation` was changed"
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]
+
+[mentions."compiler/rustc_macros/src/diagnostics"]
+message = "`rustc_macros::diagnostics` was changed"
+cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@estebank"]