diff --git a/Cargo.lock b/Cargo.lock
index 4d6530508b3d7..cb1cd3cbfe557 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3920,26 +3920,47 @@ version = "0.0.0"
 dependencies = [
  "libc",
  "rustc_ast",
+ "rustc_ast_lowering",
+ "rustc_ast_passes",
  "rustc_ast_pretty",
+ "rustc_attr",
+ "rustc_borrowck",
+ "rustc_builtin_macros",
  "rustc_codegen_ssa",
+ "rustc_const_eval",
  "rustc_data_structures",
  "rustc_error_codes",
+ "rustc_error_messages",
  "rustc_errors",
+ "rustc_expand",
  "rustc_feature",
  "rustc_hir",
  "rustc_hir_analysis",
  "rustc_hir_pretty",
+ "rustc_hir_typeck",
+ "rustc_incremental",
+ "rustc_infer",
  "rustc_interface",
  "rustc_lint",
  "rustc_log",
  "rustc_macros",
  "rustc_metadata",
  "rustc_middle",
+ "rustc_mir_build",
+ "rustc_mir_dataflow",
+ "rustc_monomorphize",
  "rustc_parse",
+ "rustc_passes",
  "rustc_plugin_impl",
+ "rustc_privacy",
+ "rustc_query_system",
+ "rustc_resolve",
  "rustc_session",
  "rustc_span",
+ "rustc_symbol_mangling",
  "rustc_target",
+ "rustc_trait_selection",
+ "rustc_ty_utils",
  "serde_json",
  "tracing",
  "winapi",
diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_ast_lowering/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl
rename to compiler/rustc_ast_lowering/locales/en-US.ftl
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 21c6a2d26f4c2..8b302ac21421a 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -339,7 +339,7 @@ pub struct InclusiveRangeWithNoEnd {
 #[derive(Diagnostic, Clone, Copy)]
 #[diag(ast_lowering_trait_fn_async, code = "E0706")]
 #[note]
-#[note(note2)]
+#[note(ast_lowering_note2)]
 pub struct TraitFnAsync {
     #[primary_span]
     pub fn_span: Span,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index b1b9344d2535c..a726fbb72e9cb 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -52,15 +52,20 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{DiagnosticArgFromDisplay, Handler, StashKey};
+use rustc_errors::{
+    DiagnosticArgFromDisplay, DiagnosticMessage, Handler, StashKey, SubdiagnosticMessage,
+};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::span_bug;
-use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
+use rustc_macros::fluent_messages;
+use rustc_middle::{
+    span_bug,
+    ty::{ResolverAstLowering, TyCtxt},
+};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DesugaringKind;
@@ -87,6 +92,8 @@ mod lifetime_collector;
 mod pat;
 mod path;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 struct LoweringContext<'a, 'hir> {
     tcx: TyCtxt<'hir>,
     resolver: &'a mut ResolverAstLowering,
diff --git a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl b/compiler/rustc_ast_passes/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
rename to compiler/rustc_ast_passes/locales/en-US.ftl
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index afa29a510d22a..56977e45a1a84 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,7 +13,7 @@ use rustc_ast::walk_list;
 use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
+use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
 use rustc_macros::Subdiagnostic;
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
@@ -30,6 +30,7 @@ use std::ops::{Deref, DerefMut};
 use thin_vec::thin_vec;
 
 use crate::errors::*;
+use crate::fluent_generated as fluent;
 
 const MORE_EXTERN: &str =
     "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
@@ -1723,12 +1724,12 @@ pub(crate) enum ForbiddenLetReason {
     /// `let` is not valid and the source environment is not important
     GenericForbidden,
     /// A let chain with the `||` operator
-    #[note(not_supported_or)]
+    #[note(ast_passes_not_supported_or)]
     NotSupportedOr(#[primary_span] Span),
     /// A let chain with invalid parentheses
     ///
     /// For example, `let 1 = 1 && (expr && expr)` is allowed
     /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
-    #[note(not_supported_parentheses)]
+    #[note(ast_passes_not_supported_parentheses)]
     NotSupportedParentheses(#[primary_span] Span),
 }
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 09e262452b11d..69ce8daa45506 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -50,7 +50,7 @@ pub struct InvalidLabel {
 pub struct InvalidVisibility {
     #[primary_span]
     pub span: Span,
-    #[label(implied)]
+    #[label(ast_passes_implied)]
     pub implied: Option<Span>,
     #[subdiagnostic]
     pub note: Option<InvalidVisibilityNote>,
@@ -58,9 +58,9 @@ pub struct InvalidVisibility {
 
 #[derive(Subdiagnostic)]
 pub enum InvalidVisibilityNote {
-    #[note(individual_impl_items)]
+    #[note(ast_passes_individual_impl_items)]
     IndividualImplItems,
-    #[note(individual_foreign_items)]
+    #[note(ast_passes_individual_foreign_items)]
     IndividualForeignItems,
 }
 
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 6f7ba7a5ad77c..d69c84bf4d1d2 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -157,7 +157,7 @@ impl<'a> PostExpansionVisitor<'a> {
                 &self.sess.parse_sess,
                 sym::non_lifetime_binders,
                 non_lt_param_spans,
-                rustc_errors::fluent::ast_passes_forbidden_non_lifetime_param,
+                crate::fluent_generated::ast_passes_forbidden_non_lifetime_param,
             )
             .emit();
         }
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index bbcbecd81313d..1be959b0de6f9 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -11,8 +11,13 @@
 #![feature(let_chains)]
 #![recursion_limit = "256"]
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 pub mod ast_validation;
 mod errors;
 pub mod feature_gate;
 pub mod node_count;
 pub mod show_span;
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_error_messages/locales/en-US/attr.ftl b/compiler/rustc_attr/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/attr.ftl
rename to compiler/rustc_attr/locales/en-US.ftl
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index 4580ffcc6d8be..5fede0a58ac1f 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -11,6 +11,9 @@
 #[macro_use]
 extern crate rustc_macros;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 mod builtin;
 mod session_diagnostics;
 
@@ -22,3 +25,5 @@ pub use StabilityLevel::*;
 pub use rustc_ast::attr::*;
 
 pub(crate) use rustc_ast::HashStableContext;
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 3ba7a3c5336b2..ee79545e304ae 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -2,11 +2,12 @@ use std::num::IntErrorKind;
 
 use rustc_ast as ast;
 use rustc_errors::{
-    error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
 };
 use rustc_macros::Diagnostic;
 use rustc_span::{Span, Symbol};
 
+use crate::fluent_generated as fluent;
 use crate::UnsupportedLiteralReason;
 
 #[derive(Diagnostic)]
@@ -59,7 +60,7 @@ impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
         );
         diag.set_arg("item", self.item);
         diag.set_arg("expected", expected.join(", "));
-        diag.span_label(self.span, fluent::label);
+        diag.span_label(self.span, fluent::attr_label);
         diag
     }
 }
@@ -99,31 +100,31 @@ pub(crate) struct InvalidIssueString {
 // translatable.
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidIssueStringCause {
-    #[label(must_not_be_zero)]
+    #[label(attr_must_not_be_zero)]
     MustNotBeZero {
         #[primary_span]
         span: Span,
     },
 
-    #[label(empty)]
+    #[label(attr_empty)]
     Empty {
         #[primary_span]
         span: Span,
     },
 
-    #[label(invalid_digit)]
+    #[label(attr_invalid_digit)]
     InvalidDigit {
         #[primary_span]
         span: Span,
     },
 
-    #[label(pos_overflow)]
+    #[label(attr_pos_overflow)]
     PosOverflow {
         #[primary_span]
         span: Span,
     },
 
-    #[label(neg_overflow)]
+    #[label(attr_neg_overflow)]
     NegOverflow {
         #[primary_span]
         span: Span,
@@ -275,7 +276,7 @@ pub(crate) struct IncorrectReprFormatGeneric<'a> {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum IncorrectReprFormatGenericCause<'a> {
-    #[suggestion(suggestion, code = "{name}({int})", applicability = "machine-applicable")]
+    #[suggestion(attr_suggestion, code = "{name}({int})", applicability = "machine-applicable")]
     Int {
         #[primary_span]
         span: Span,
@@ -287,7 +288,7 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> {
         int: u128,
     },
 
-    #[suggestion(suggestion, code = "{name}({symbol})", applicability = "machine-applicable")]
+    #[suggestion(attr_suggestion, code = "{name}({symbol})", applicability = "machine-applicable")]
     Symbol {
         #[primary_span]
         span: Span,
diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_borrowck/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/borrowck.ftl
rename to compiler/rustc_borrowck/locales/en-US.ftl
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 622b57c7b7f2b..4294914343121 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -20,7 +20,7 @@ extern crate tracing;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::{Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::ChunkedBitSet;
@@ -28,6 +28,7 @@ use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{
     DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
 };
+use rustc_macros::fluent_messages;
 use rustc_middle::mir::{
     traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
     Place, PlaceElem, PlaceRef, VarDebugInfoContents,
@@ -99,6 +100,8 @@ use places_conflict::{places_conflict, PlaceConflictBias};
 use region_infer::RegionInferenceContext;
 use renumber::RegionCtxt;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 // FIXME(eddyb) perhaps move this somewhere more centrally.
 #[derive(Debug)]
 struct Upvar<'tcx> {
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 13199d0385255..a3678929099d1 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -55,7 +55,7 @@ pub(crate) struct VarNeedNotMut {
 #[derive(Diagnostic)]
 #[diag(borrowck_var_cannot_escape_closure)]
 #[note]
-#[note(cannot_escape)]
+#[note(borrowck_cannot_escape)]
 pub(crate) struct FnMutError {
     #[primary_span]
     pub span: Span,
@@ -223,7 +223,7 @@ pub(crate) struct MoveBorrow<'a> {
     pub borrow_place: &'a str,
     pub value_place: &'a str,
     #[primary_span]
-    #[label(move_label)]
+    #[label(borrowck_move_label)]
     pub span: Span,
     #[label]
     pub borrow_span: Span,
diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_builtin_macros/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
rename to compiler/rustc_builtin_macros/locales/en-US.ftl
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 75cfac7238485..8afb6e56069b0 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -21,8 +21,10 @@ extern crate tracing;
 
 use crate::deriving::*;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
+use rustc_macros::fluent_messages;
 use rustc_span::symbol::sym;
 
 mod alloc_error_handler;
@@ -54,6 +56,8 @@ pub mod proc_macro_harness;
 pub mod standard_library_imports;
 pub mod test_harness;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     let mut register = |name, kind| resolver.register_builtin_macro(name, kind);
     macro register_bang($($name:ident: $f:expr,)*) {
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index c7fe382bac4e3..5ba568bfd6e87 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -172,6 +172,11 @@ pub struct CraneliftCodegenBackend {
 }
 
 impl CodegenBackend for CraneliftCodegenBackend {
+    fn locale_resource(&self) -> &'static str {
+        // FIXME(rust-lang/rust#100717) - cranelift codegen backend is not yet translated
+        ""
+    }
+
     fn init(&self, sess: &Session) {
         use rustc_session::config::Lto;
         match sess.lto() {
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl b/compiler/rustc_codegen_gcc/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl
rename to compiler/rustc_codegen_gcc/locales/en-US.ftl
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 5ab87feb98b11..44538b415283c 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -73,7 +73,8 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul
 use rustc_codegen_ssa::target_features::supported_target_features;
 use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{ErrorGuaranteed, Handler};
+use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
@@ -84,6 +85,8 @@ use rustc_span::Symbol;
 use rustc_span::fatal_error::FatalError;
 use tempfile::TempDir;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub struct PrintOnPanic<F: Fn() -> String>(pub F);
 
 impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
@@ -100,6 +103,10 @@ pub struct GccCodegenBackend {
 }
 
 impl CodegenBackend for GccCodegenBackend {
+    fn locale_resource(&self) -> &'static str {
+        crate::DEFAULT_LOCALE_RESOURCE
+    }
+
     fn init(&self, sess: &Session) {
         if sess.lto() != Lto::No {
             sess.emit_warning(LTONotSupported {});
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl b/compiler/rustc_codegen_llvm/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
rename to compiler/rustc_codegen_llvm/locales/en-US.ftl
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index 81072edc475c4..bae88d942934c 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -2,9 +2,10 @@ use std::borrow::Cow;
 use std::ffi::CString;
 use std::path::Path;
 
+use crate::fluent_generated as fluent;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{
-    fluent, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic,
+    DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::Span;
@@ -27,9 +28,9 @@ pub(crate) struct UnknownCTargetFeature<'a> {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum PossibleFeature<'a> {
-    #[help(possible_feature)]
+    #[help(codegen_llvm_possible_feature)]
     Some { rust_feature: &'a str },
-    #[help(consider_filing_feature_request)]
+    #[help(codegen_llvm_consider_filing_feature_request)]
     None,
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 111d14b265cde..c41e74c51a0db 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -34,7 +34,8 @@ use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{ErrorGuaranteed, FatalError, Handler};
+use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, FatalError, Handler, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::query::Providers;
@@ -83,6 +84,8 @@ mod type_of;
 mod va_arg;
 mod value;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 #[derive(Clone)]
 pub struct LlvmCodegenBackend(());
 
@@ -246,6 +249,10 @@ impl LlvmCodegenBackend {
 }
 
 impl CodegenBackend for LlvmCodegenBackend {
+    fn locale_resource(&self) -> &'static str {
+        crate::DEFAULT_LOCALE_RESOURCE
+    }
+
     fn init(&self, sess: &Session) {
         llvm_util::init(sess); // Make sure llvm is inited
     }
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_codegen_ssa/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
rename to compiler/rustc_codegen_ssa/locales/en-US.ftl
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index d81252653dfe8..6dea7496fc3e6 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,8 +1,9 @@
 //! Errors emitted by codegen_ssa
 
 use crate::back::command::Command;
+use crate::fluent_generated as fluent;
 use rustc_errors::{
-    fluent, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
     IntoDiagnosticArg,
 };
 use rustc_macros::Diagnostic;
@@ -388,7 +389,7 @@ pub struct LinkerNotFound {
 #[derive(Diagnostic)]
 #[diag(codegen_ssa_unable_to_exe_linker)]
 #[note]
-#[note(command_note)]
+#[note(codegen_ssa_command_note)]
 pub struct UnableToExeLinker {
     pub linker_path: PathBuf,
     pub error: Error,
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 7d51cee307e92..ebe9e50ffe66d 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -25,7 +25,9 @@ extern crate rustc_middle;
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir::def_id::CrateNum;
+use rustc_macros::fluent_messages;
 use rustc_middle::dep_graph::WorkProduct;
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
@@ -54,6 +56,8 @@ pub mod mono_item;
 pub mod target_features;
 pub mod traits;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub struct ModuleCodegen<M> {
     /// The name of the module. When the crate may be saved between
     /// compilations, incremental compilation requires that name be
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 5c35070ea66f4..64bebe50ddbf2 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -57,6 +57,10 @@ impl<'tcx, T> Backend<'tcx> for T where
 }
 
 pub trait CodegenBackend {
+    /// Locale resources for diagnostic messages - a string the content of the Fluent resource.
+    /// Called before `init` so that all other functions are able to emit translatable diagnostics.
+    fn locale_resource(&self) -> &'static str;
+
     fn init(&self, _sess: &Session) {}
     fn print(&self, _req: PrintRequest, _sess: &Session) {}
     fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
diff --git a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl b/compiler/rustc_const_eval/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/const_eval.ftl
rename to compiler/rustc_const_eval/locales/en-US.ftl
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 4b055076742b2..f8b7cc6d7e16b 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -9,12 +9,12 @@ pub(crate) struct UnstableInStable {
     #[primary_span]
     pub span: Span,
     #[suggestion(
-        unstable_sugg,
+        const_eval_unstable_sugg,
         code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
         applicability = "has-placeholders"
     )]
     #[suggestion(
-        bypass_sugg,
+        const_eval_bypass_sugg,
         code = "#[rustc_allow_const_fn_unstable({gate})]\n",
         applicability = "has-placeholders"
     )]
@@ -35,15 +35,15 @@ pub(crate) struct StaticAccessErr {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(teach_note)]
-    #[help(teach_help)]
+    #[note(const_eval_teach_note)]
+    #[help(const_eval_teach_help)]
     pub teach: Option<()>,
 }
 
 #[derive(Diagnostic)]
 #[diag(const_eval_raw_ptr_to_int)]
 #[note]
-#[note(note2)]
+#[note(const_eval_note2)]
 pub(crate) struct RawPtrToIntErr {
     #[primary_span]
     pub span: Span,
@@ -118,7 +118,7 @@ pub(crate) struct UnallowedMutableRefs {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(teach_note)]
+    #[note(const_eval_teach_note)]
     pub teach: Option<()>,
 }
 
@@ -128,7 +128,7 @@ pub(crate) struct UnallowedMutableRefsRaw {
     #[primary_span]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(teach_note)]
+    #[note(const_eval_teach_note)]
     pub teach: Option<()>,
 }
 #[derive(Diagnostic)]
@@ -163,7 +163,7 @@ pub(crate) struct UnallowedHeapAllocations {
     #[label]
     pub span: Span,
     pub kind: ConstContext,
-    #[note(teach_note)]
+    #[note(const_eval_teach_note)]
     pub teach: Option<()>,
 }
 
@@ -184,7 +184,7 @@ pub(crate) struct InteriorMutableDataRefer {
     #[help]
     pub opt_help: Option<()>,
     pub kind: ConstContext,
-    #[note(teach_note)]
+    #[note(const_eval_teach_note)]
     pub teach: Option<()>,
 }
 
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 964efcc9062db..fc6d61c79c2c4 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -34,10 +34,14 @@ pub mod interpret;
 pub mod transform;
 pub mod util;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
 use rustc_middle::ty;
 use rustc_middle::ty::query::Providers;
 use rustc_target::abi::InitKind;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub fn provide(providers: &mut Providers) {
     const_eval::provide(providers);
     providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index cdec4f912779c..7b59a52cffeda 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -9,6 +9,27 @@ edition = "2021"
 tracing = { version = "0.1.35" }
 serde_json = "1.0.59"
 rustc_log = { path = "../rustc_log" }
+rustc_ast_lowering = { path = "../rustc_ast_lowering" }
+rustc_ast_passes = { path = "../rustc_ast_passes" }
+rustc_attr = { path = "../rustc_attr" }
+rustc_borrowck = { path = "../rustc_borrowck" }
+rustc_builtin_macros = { path = "../rustc_builtin_macros" }
+rustc_const_eval = { path = "../rustc_const_eval" }
+rustc_error_messages = { path = "../rustc_error_messages" }
+rustc_expand = { path = "../rustc_expand" }
+rustc_hir_typeck = { path = "../rustc_hir_typeck" }
+rustc_incremental = { path = "../rustc_incremental" }
+rustc_infer = { path = "../rustc_infer" }
+rustc_mir_build = { path = "../rustc_mir_build" }
+rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
+rustc_monomorphize = { path = "../rustc_monomorphize" }
+rustc_passes = { path = "../rustc_passes" }
+rustc_privacy = { path = "../rustc_privacy" }
+rustc_query_system = { path = "../rustc_query_system" }
+rustc_resolve = { path = "../rustc_resolve" }
+rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_ty_utils = { path = "../rustc_ty_utils" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_error_messages/locales/en-US/driver.ftl b/compiler/rustc_driver_impl/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/driver.ftl
rename to compiler/rustc_driver_impl/locales/en-US.ftl
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index d7e9e00f3b63b..54bcb154da28f 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -23,11 +23,14 @@ use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
-use rustc_errors::{ErrorGuaranteed, PResult, TerminalUrl};
+use rustc_errors::{
+    DiagnosticMessage, ErrorGuaranteed, PResult, SubdiagnosticMessage, TerminalUrl,
+};
 use rustc_feature::find_gated_cfg;
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
 use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
+use rustc_macros::fluent_messages;
 use rustc_metadata::locator;
 use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
 use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
@@ -61,6 +64,44 @@ use crate::session_diagnostics::{
     RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead,
 };
 
+fluent_messages! { "../locales/en-US.ftl" }
+
+pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
+    // tidy-alphabetical-start
+    crate::DEFAULT_LOCALE_RESOURCE,
+    rustc_ast_lowering::DEFAULT_LOCALE_RESOURCE,
+    rustc_ast_passes::DEFAULT_LOCALE_RESOURCE,
+    rustc_attr::DEFAULT_LOCALE_RESOURCE,
+    rustc_borrowck::DEFAULT_LOCALE_RESOURCE,
+    rustc_builtin_macros::DEFAULT_LOCALE_RESOURCE,
+    rustc_codegen_ssa::DEFAULT_LOCALE_RESOURCE,
+    rustc_const_eval::DEFAULT_LOCALE_RESOURCE,
+    rustc_error_messages::DEFAULT_LOCALE_RESOURCE,
+    rustc_expand::DEFAULT_LOCALE_RESOURCE,
+    rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE,
+    rustc_hir_typeck::DEFAULT_LOCALE_RESOURCE,
+    rustc_incremental::DEFAULT_LOCALE_RESOURCE,
+    rustc_infer::DEFAULT_LOCALE_RESOURCE,
+    rustc_interface::DEFAULT_LOCALE_RESOURCE,
+    rustc_lint::DEFAULT_LOCALE_RESOURCE,
+    rustc_metadata::DEFAULT_LOCALE_RESOURCE,
+    rustc_middle::DEFAULT_LOCALE_RESOURCE,
+    rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
+    rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
+    rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
+    rustc_parse::DEFAULT_LOCALE_RESOURCE,
+    rustc_passes::DEFAULT_LOCALE_RESOURCE,
+    rustc_plugin_impl::DEFAULT_LOCALE_RESOURCE,
+    rustc_privacy::DEFAULT_LOCALE_RESOURCE,
+    rustc_query_system::DEFAULT_LOCALE_RESOURCE,
+    rustc_resolve::DEFAULT_LOCALE_RESOURCE,
+    rustc_session::DEFAULT_LOCALE_RESOURCE,
+    rustc_symbol_mangling::DEFAULT_LOCALE_RESOURCE,
+    rustc_trait_selection::DEFAULT_LOCALE_RESOURCE,
+    rustc_ty_utils::DEFAULT_LOCALE_RESOURCE,
+    // tidy-alphabetical-end
+];
+
 /// Exit status code used for successful compilation and help output.
 pub const EXIT_SUCCESS: i32 = 0;
 
@@ -218,6 +259,7 @@ fn run_compiler(
         output_file: ofile,
         output_dir: odir,
         file_loader,
+        locale_resources: DEFAULT_LOCALE_RESOURCES,
         lint_caps: Default::default(),
         parse_sess_created: None,
         register_lints: None,
@@ -1162,7 +1204,7 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
 /// hook.
 pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     let fallback_bundle =
-        rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+        rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
     let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
         rustc_errors::ColorConfig::Auto,
         None,
diff --git a/compiler/rustc_error_messages/locales/en-US.ftl b/compiler/rustc_error_messages/locales/en-US.ftl
new file mode 100644
index 0000000000000..e629237444822
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US.ftl
@@ -0,0 +1 @@
+# satisfy tidy lint by having a line in this file
diff --git a/compiler/rustc_error_messages/locales/en-US/errors.ftl b/compiler/rustc_error_messages/locales/en-US/errors.ftl
deleted file mode 100644
index 429bdd2777f91..0000000000000
--- a/compiler/rustc_error_messages/locales/en-US/errors.ftl
+++ /dev/null
@@ -1,13 +0,0 @@
-errors_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
-
-errors_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
-
-errors_target_missing_alignment = missing alignment for `{$cause}` in "data-layout"
-
-errors_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err}
-
-errors_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
-
-errors_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
-
-errors_target_invalid_bits_size = {$err}
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 579466ed366d8..40ed10e716597 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -34,47 +34,7 @@ use intl_memoizer::IntlLangMemoizer;
 pub use fluent_bundle::{self, types::FluentType, FluentArgs, FluentError, FluentValue};
 pub use unic_langid::{langid, LanguageIdentifier};
 
-// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
-fluent_messages! {
-    // tidy-alphabetical-start
-    ast_lowering => "../locales/en-US/ast_lowering.ftl",
-    ast_passes => "../locales/en-US/ast_passes.ftl",
-    attr => "../locales/en-US/attr.ftl",
-    borrowck => "../locales/en-US/borrowck.ftl",
-    builtin_macros => "../locales/en-US/builtin_macros.ftl",
-    codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
-    codegen_llvm => "../locales/en-US/codegen_llvm.ftl",
-    codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
-    compiletest => "../locales/en-US/compiletest.ftl",
-    const_eval => "../locales/en-US/const_eval.ftl",
-    driver => "../locales/en-US/driver.ftl",
-    errors => "../locales/en-US/errors.ftl",
-    expand => "../locales/en-US/expand.ftl",
-    hir_analysis => "../locales/en-US/hir_analysis.ftl",
-    hir_typeck => "../locales/en-US/hir_typeck.ftl",
-    incremental => "../locales/en-US/incremental.ftl",
-    infer => "../locales/en-US/infer.ftl",
-    interface => "../locales/en-US/interface.ftl",
-    lint => "../locales/en-US/lint.ftl",
-    metadata => "../locales/en-US/metadata.ftl",
-    middle => "../locales/en-US/middle.ftl",
-    mir_build => "../locales/en-US/mir_build.ftl",
-    mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
-    monomorphize => "../locales/en-US/monomorphize.ftl",
-    parse => "../locales/en-US/parse.ftl",
-    passes => "../locales/en-US/passes.ftl",
-    plugin_impl => "../locales/en-US/plugin_impl.ftl",
-    privacy => "../locales/en-US/privacy.ftl",
-    query_system => "../locales/en-US/query_system.ftl",
-    resolve => "../locales/en-US/resolve.ftl",
-    session => "../locales/en-US/session.ftl",
-    symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
-    trait_selection => "../locales/en-US/trait_selection.ftl",
-    ty_utils => "../locales/en-US/ty_utils.ftl",
-    // tidy-alphabetical-end
-}
-
-pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
+fluent_messages! { "../locales/en-US.ftl" }
 
 pub type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>;
 
@@ -263,7 +223,7 @@ pub type LazyFallbackBundle = Lrc<Lazy<FluentBundle, impl FnOnce() -> FluentBund
 /// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
 #[instrument(level = "trace")]
 pub fn fallback_fluent_bundle(
-    resources: &'static [&'static str],
+    resources: Vec<&'static str>,
     with_directionality_markers: bool,
 ) -> LazyFallbackBundle {
     Lrc::new(Lazy::new(move || {
diff --git a/compiler/rustc_errors/locales/en-US.ftl b/compiler/rustc_errors/locales/en-US.ftl
new file mode 100644
index 0000000000000..dde1d6c0a819c
--- /dev/null
+++ b/compiler/rustc_errors/locales/en-US.ftl
@@ -0,0 +1,19 @@
+errors_target_invalid_address_space =
+    invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
+
+errors_target_invalid_bits =
+    invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
+
+errors_target_missing_alignment =
+    missing alignment for `{$cause}` in "data-layout"
+
+errors_target_invalid_alignment =
+    invalid alignment for `{$cause}` in "data-layout": {$err}
+
+errors_target_inconsistent_architecture =
+    inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
+
+errors_target_inconsistent_pointer_width =
+    inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
+
+errors_target_invalid_bits_size = {$err}
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 5ada85d04b0bc..d4ddd0c53bfdd 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,6 +1,5 @@
-use crate::{
-    fluent, DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg,
-};
+use crate::fluent_generated as fluent;
+use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg};
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_hir as hir;
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index f161532d3b7e2..671dc449eaa73 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -46,7 +46,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned());
         let fallback_bundle =
-            crate::fallback_fluent_bundle(rustc_error_messages::DEFAULT_LOCALE_RESOURCES, false);
+            crate::fallback_fluent_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false);
 
         let output = Arc::new(Mutex::new(Vec::new()));
         let je = JsonEmitter::new(
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 8c39feca88a0e..edec8cce92f97 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -36,11 +36,11 @@ use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{self, Lock, Lrc};
 use rustc_data_structures::AtomicRef;
 pub use rustc_error_messages::{
-    fallback_fluent_bundle, fluent, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
+    fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
     LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage,
-    DEFAULT_LOCALE_RESOURCES,
 };
 pub use rustc_lint_defs::{pluralize, Applicability};
+use rustc_macros::fluent_messages;
 use rustc_span::source_map::SourceMap;
 use rustc_span::HashStableContext;
 use rustc_span::{Loc, Span};
@@ -76,6 +76,8 @@ pub use snippet::Style;
 pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>;
 pub type PResult<'a, T> = Result<T, PErr<'a>>;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
 // (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.)
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
index addfc9726ca44..1ac9b8e03c7c3 100644
--- a/compiler/rustc_errors/src/translation.rs
+++ b/compiler/rustc_errors/src/translation.rs
@@ -4,6 +4,7 @@ use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
 use rustc_data_structures::sync::Lrc;
 use rustc_error_messages::FluentArgs;
 use std::borrow::Cow;
+use std::env;
 use std::error::Report;
 
 /// Convert diagnostic arguments (a rustc internal type that exists to implement
@@ -94,8 +95,16 @@ pub trait Translate {
                 // The primary bundle was present and translation succeeded
                 Some(Ok(t)) => t,
 
-                // Always yeet out for errors on debug
-                Some(Err(primary)) if cfg!(debug_assertions) => do yeet primary,
+                // Always yeet out for errors on debug (unless
+                // `RUSTC_TRANSLATION_NO_DEBUG_ASSERT` is set in the environment - this allows
+                // local runs of the test suites, of builds with debug assertions, to test the
+                // behaviour in a normal build).
+                Some(Err(primary))
+                    if cfg!(debug_assertions)
+                        && env::var("RUSTC_TRANSLATION_NO_DEBUG_ASSERT").is_err() =>
+                {
+                    do yeet primary
+                }
 
                 // If `translate_with_bundle` returns `Err` with the primary bundle, this is likely
                 // just that the primary bundle doesn't contain the message being translated or
diff --git a/compiler/rustc_error_messages/locales/en-US/expand.ftl b/compiler/rustc_expand/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/expand.ftl
rename to compiler/rustc_expand/locales/en-US.ftl
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 9b9697ab13d26..d9b2b5f4802c8 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -65,7 +65,7 @@ pub(crate) struct MacroConstStability {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(label2)]
+    #[label(expand_label2)]
     pub head_span: Span,
 }
 
@@ -75,7 +75,7 @@ pub(crate) struct MacroBodyStability {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(label2)]
+    #[label(expand_label2)]
     pub head_span: Span,
 }
 
@@ -188,7 +188,7 @@ pub(crate) struct FeatureRemoved<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[note(reason)]
+#[note(expand_reason)]
 pub(crate) struct FeatureRemovedReason<'a> {
     pub reason: &'a str,
 }
@@ -223,12 +223,12 @@ pub(crate) struct MalformedFeatureAttribute {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum MalformedFeatureAttributeHelp {
-    #[label(expected)]
+    #[label(expand_expected)]
     Label {
         #[primary_span]
         span: Span,
     },
-    #[suggestion(expected, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(expand_expected, code = "{suggestion}", applicability = "maybe-incorrect")]
     Suggestion {
         #[primary_span]
         span: Span,
@@ -306,7 +306,7 @@ pub(crate) struct IncompleteParse<'a> {
     pub kind_name: &'a str,
 
     #[suggestion(
-        suggestion_add_semi,
+        expand_suggestion_add_semi,
         style = "verbose",
         code = ";",
         applicability = "maybe-incorrect"
@@ -340,7 +340,7 @@ pub(crate) struct ModuleInBlock {
 }
 
 #[derive(Subdiagnostic)]
-#[note(note)]
+#[note(expand_note)]
 pub(crate) struct ModuleInBlockName {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 897268566358a..634e206e58ab4 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -20,6 +20,9 @@ extern crate tracing;
 
 extern crate proc_macro as pm;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 mod placeholders;
 mod proc_macro_server;
 
@@ -60,3 +63,5 @@ mod tokenstream {
 mod mut_visit {
     mod tests;
 }
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index 0726d922c84a3..8b37728b60fea 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -18,7 +18,10 @@ use rustc_span::{BytePos, FileName, Pos, Span};
 use std::path::PathBuf;
 
 fn sess() -> ParseSess {
-    ParseSess::new(FilePathMapping::empty())
+    ParseSess::new(
+        vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
+        FilePathMapping::empty(),
+    )
 }
 
 /// Parses an item.
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index f80141403bf15..14918d3c190a5 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -34,7 +34,10 @@ where
 
 /// Maps a string to tts, using a made-up filename.
 pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
-    let ps = ParseSess::new(FilePathMapping::empty());
+    let ps = ParseSess::new(
+        vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
+        FilePathMapping::empty(),
+    );
     source_file_to_stream(
         &ps,
         ps.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str),
@@ -45,7 +48,10 @@ pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
 
 /// Parses a string, returns a crate.
 pub(crate) fn string_to_crate(source_str: String) -> ast::Crate {
-    let ps = ParseSess::new(FilePathMapping::empty());
+    let ps = ParseSess::new(
+        vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
+        FilePathMapping::empty(),
+    );
     with_error_checking_parse(source_str, &ps, |p| p.parse_crate_mod())
 }
 
@@ -127,8 +133,10 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
     create_default_session_if_not_set_then(|_| {
         let output = Arc::new(Mutex::new(Vec::new()));
 
-        let fallback_bundle =
-            rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+        let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+            vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE],
+            false,
+        );
         let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
 
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_hir_analysis/locales/en-US.ftl
similarity index 98%
rename from compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
rename to compiler/rustc_hir_analysis/locales/en-US.ftl
index f8d28817fec88..aa56e60ec7539 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
+++ b/compiler/rustc_hir_analysis/locales/en-US.ftl
@@ -33,20 +33,7 @@ hir_analysis_field_already_declared =
     .label = field already declared
     .previous_decl_label = `{$field_name}` first declared here
 
-hir_analysis_copy_impl_on_type_with_dtor =
-    the trait `Copy` may not be implemented for this type; the type has a destructor
-    .label = `Copy` not allowed on types with destructors
-
-hir_analysis_multiple_relaxed_default_bounds =
-    type parameter has more than one relaxed default bound, only one is supported
-
-hir_analysis_copy_impl_on_non_adt =
-    the trait `Copy` may not be implemented for this type
-    .label = type is not a structure or enumeration
-
-hir_analysis_trait_object_declared_with_no_traits =
-    at least one trait is required for an object type
-    .alias_span = this alias does not contain a trait
+hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
 
 hir_analysis_ambiguous_lifetime_bound =
     ambiguous lifetime bound, explicit lifetime bound required
@@ -68,6 +55,25 @@ hir_analysis_value_of_associated_struct_already_specified =
 hir_analysis_unconstrained_opaque_type = unconstrained opaque type
     .note = `{$name}` must be used in combination with a concrete type within the same {$what}
 
+hir_analysis_manual_implementation =
+    manual implementations of `{$trait_name}` are experimental
+    .label = manual implementations of `{$trait_name}` are experimental
+    .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable
+
+hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
+
+hir_analysis_unused_extern_crate =
+    unused extern crate
+    .suggestion = remove it
+
+hir_analysis_extern_crate_not_idiomatic =
+    `extern crate` is not idiomatic in the new edition
+    .suggestion = convert it to a `{$msg_code}`
+
+hir_analysis_trait_object_declared_with_no_traits =
+    at least one trait is required for an object type
+    .alias_span = this alias does not contain a trait
+
 hir_analysis_missing_type_params =
     the type {$parameterCount ->
         [one] parameter
@@ -90,20 +96,16 @@ hir_analysis_missing_type_params =
     } to {$parameters}
     .note = because of the default `Self` reference, type parameters must be specified on object types
 
-hir_analysis_manual_implementation =
-    manual implementations of `{$trait_name}` are experimental
-    .label = manual implementations of `{$trait_name}` are experimental
-    .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable
-
-hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
+hir_analysis_copy_impl_on_type_with_dtor =
+    the trait `Copy` may not be implemented for this type; the type has a destructor
+    .label = `Copy` not allowed on types with destructors
 
-hir_analysis_unused_extern_crate =
-    unused extern crate
-    .suggestion = remove it
+hir_analysis_multiple_relaxed_default_bounds =
+    type parameter has more than one relaxed default bound, only one is supported
 
-hir_analysis_extern_crate_not_idiomatic =
-    `extern crate` is not idiomatic in the new edition
-    .suggestion = convert it to a `{$msg_code}`
+hir_analysis_copy_impl_on_non_adt =
+    the trait `Copy` may not be implemented for this type
+    .label = type is not a structure or enumeration
 
 hir_analysis_const_impl_for_non_const_trait =
     const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index f3c3c02a05f3f..be3ef03192c26 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1,7 +1,10 @@
 //! Errors emitted by `rustc_hir_analysis`.
 
-use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
-use rustc_errors::{IntoDiagnostic, MultiSpan};
+use crate::fluent_generated as fluent;
+use rustc_errors::{
+    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    MultiSpan,
+};
 use rustc_macros::{Diagnostic, LintDiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
@@ -41,11 +44,11 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(generics_label)]
+    #[label(hir_analysis_generics_label)]
     pub generics_span: Option<Span>,
-    #[label(where_label)]
+    #[label(hir_analysis_where_label)]
     pub where_span: Option<Span>,
-    #[label(bounds_label)]
+    #[label(hir_analysis_bounds_label)]
     pub bounds_span: Vec<Span>,
     pub item_kind: &'static str,
     pub ident: Ident,
@@ -57,7 +60,7 @@ pub struct AsyncTraitImplShouldBeAsync {
     #[primary_span]
     // #[label]
     pub span: Span,
-    #[label(trait_item_label)]
+    #[label(hir_analysis_trait_item_label)]
     pub trait_item_span: Option<Span>,
     pub method_name: Symbol,
 }
@@ -77,7 +80,7 @@ pub struct FieldAlreadyDeclared {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(previous_decl_label)]
+    #[label(hir_analysis_previous_decl_label)]
     pub prev_span: Span,
 }
 
@@ -109,7 +112,7 @@ pub struct CopyImplOnNonAdt {
 pub struct TraitObjectDeclaredWithNoTraits {
     #[primary_span]
     pub span: Span,
-    #[label(alias_span)]
+    #[label(hir_analysis_alias_span)]
     pub trait_alias_span: Option<Span>,
 }
 
@@ -145,7 +148,7 @@ pub struct ValueOfAssociatedStructAlreadySpecified {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(previous_bound_label)]
+    #[label(hir_analysis_previous_bound_label)]
     pub prev_span: Span,
     pub item_name: Ident,
     pub def_path: String,
@@ -175,7 +178,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut err = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::hir_analysis_missing_type_params,
+            fluent::hir_analysis_missing_type_params,
             error_code!(E0393),
         );
         err.set_arg("parameterCount", self.missing_type_params.len());
@@ -188,7 +191,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
                 .join(", "),
         );
 
-        err.span_label(self.def_span, rustc_errors::fluent::label);
+        err.span_label(self.def_span, fluent::hir_analysis_label);
 
         let mut suggested = false;
         // Don't suggest setting the type params if there are some already: the order is
@@ -203,7 +206,7 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
                 // least we can clue them to the correct syntax `Iterator<Type>`.
                 err.span_suggestion(
                     self.span,
-                    rustc_errors::fluent::suggestion,
+                    fluent::hir_analysis_suggestion,
                     format!(
                         "{}<{}>",
                         snippet,
@@ -219,10 +222,10 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
             }
         }
         if !suggested {
-            err.span_label(self.span, rustc_errors::fluent::no_suggestion_label);
+            err.span_label(self.span, fluent::hir_analysis_no_suggestion_label);
         }
 
-        err.note(rustc_errors::fluent::note);
+        err.note(fluent::hir_analysis_note);
         err
     }
 }
@@ -274,7 +277,7 @@ pub struct ConstImplForNonConstTrait {
     pub local_trait_span: Option<Span>,
     #[note]
     pub marking: (),
-    #[note(adding)]
+    #[note(hir_analysis_adding)]
     pub adding: (),
 }
 
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 73a7137666264..d54e569905fa8 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -99,9 +99,11 @@ pub mod structured_errors;
 mod variance;
 
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
+use rustc_macros::fluent_messages;
 use rustc_middle::middle;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -118,6 +120,8 @@ use std::ops::Not;
 use astconv::AstConv;
 use bounds::Bounds;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
     const ERROR_HEAD: &str = "C-variadic function must have a compatible calling convention";
     const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl b/compiler/rustc_hir_typeck/locales/en-US.ftl
similarity index 80%
rename from compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl
rename to compiler/rustc_hir_typeck/locales/en-US.ftl
index 05ac8db0db88f..adfcbc36a4d02 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl
+++ b/compiler/rustc_hir_typeck/locales/en-US.ftl
@@ -1,17 +1,26 @@
-hir_typeck_fru_note = this expression may have been misinterpreted as a `..` range expression
-hir_typeck_fru_expr = this expression does not end in a comma...
-hir_typeck_fru_expr2 = ... so this is interpreted as a `..` range expression, instead of functional record update syntax
-hir_typeck_fru_suggestion =
-    to set the remaining fields{$expr ->
-        [NONE]{""}
-        *[other] {" "}from `{$expr}`
-    }, separate the last named field with a comma
-
 hir_typeck_field_multiply_specified_in_initializer =
     field `{$ident}` specified more than once
     .label = used more than once
     .previous_use_label = first use of `{$ident}`
 
+hir_typeck_copy_impl_on_type_with_dtor =
+    the trait `Copy` may not be implemented for this type; the type has a destructor
+    .label = `Copy` not allowed on types with destructors
+
+hir_typeck_multiple_relaxed_default_bounds =
+    type parameter has more than one relaxed default bound, only one is supported
+
+hir_typeck_copy_impl_on_non_adt =
+    the trait `Copy` may not be implemented for this type
+    .label = type is not a structure or enumeration
+
+hir_typeck_trait_object_declared_with_no_traits =
+    at least one trait is required for an object type
+    .alias_span = this alias does not contain a trait
+
+hir_typeck_functional_record_update_on_non_struct =
+    functional record update syntax requires a struct
+
 hir_typeck_return_stmt_outside_of_fn_body =
     return statement outside of function body
     .encl_body_label = the return is part of this body...
@@ -26,9 +35,6 @@ hir_typeck_struct_expr_non_exhaustive =
 hir_typeck_method_call_on_unknown_type =
     the type of this value must be known to call a method on a raw pointer on it
 
-hir_typeck_functional_record_update_on_non_struct =
-    functional record update syntax requires a struct
-
 hir_typeck_address_of_temporary_taken = cannot take address of a temporary
     .label = temporary value
 
@@ -44,9 +50,6 @@ hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on
 
 hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
 
-hir_typeck_op_trait_generic_params =
-    `{$method_name}` must not have any generic parameters
-
 hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
 hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
 
@@ -63,3 +66,14 @@ hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
 hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
 
 hir_typeck_convert_to_str = try converting the passed type into a `&str`
+
+hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters
+
+hir_typeck_fru_note = this expression may have been misinterpreted as a `..` range expression
+hir_typeck_fru_expr = this expression does not end in a comma...
+hir_typeck_fru_expr2 = ... so this is interpreted as a `..` range expression, instead of functional record update syntax
+hir_typeck_fru_suggestion =
+    to set the remaining fields{$expr ->
+        [NONE]{""}
+        *[other] {" "}from `{$expr}`
+    }, separate the last named field with a comma
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 2c8979402b654..3eee2278dcadd 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -1,4 +1,5 @@
 //! Errors emitted by `rustc_hir_typeck`.
+use crate::fluent_generated as fluent;
 use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
@@ -14,7 +15,7 @@ pub struct FieldMultiplySpecifiedInInitializer {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(previous_use_label)]
+    #[label(hir_typeck_previous_use_label)]
     pub prev_span: Span,
     pub ident: Ident,
 }
@@ -24,9 +25,9 @@ pub struct FieldMultiplySpecifiedInInitializer {
 pub struct ReturnStmtOutsideOfFnBody {
     #[primary_span]
     pub span: Span,
-    #[label(encl_body_label)]
+    #[label(hir_typeck_encl_body_label)]
     pub encl_body_span: Option<Span>,
-    #[label(encl_fn_label)]
+    #[label(hir_typeck_encl_fn_label)]
     pub encl_fn_span: Option<Span>,
 }
 
@@ -157,20 +158,17 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
 
         // Only explain that `a ..b` is a range if it's split up
         if self.expr_span.between(self.fru_span).is_empty() {
-            diag.span_note(
-                self.expr_span.to(self.fru_span),
-                rustc_errors::fluent::hir_typeck_fru_note,
-            );
+            diag.span_note(self.expr_span.to(self.fru_span), fluent::hir_typeck_fru_note);
         } else {
             let mut multispan: MultiSpan = vec![self.expr_span, self.fru_span].into();
-            multispan.push_span_label(self.expr_span, rustc_errors::fluent::hir_typeck_fru_expr);
-            multispan.push_span_label(self.fru_span, rustc_errors::fluent::hir_typeck_fru_expr2);
-            diag.span_note(multispan, rustc_errors::fluent::hir_typeck_fru_note);
+            multispan.push_span_label(self.expr_span, fluent::hir_typeck_fru_expr);
+            multispan.push_span_label(self.fru_span, fluent::hir_typeck_fru_expr2);
+            diag.span_note(multispan, fluent::hir_typeck_fru_note);
         }
 
         diag.span_suggestion(
             self.expr_span.shrink_to_hi(),
-            rustc_errors::fluent::hir_typeck_fru_suggestion,
+            fluent::hir_typeck_fru_suggestion,
             ", ",
             Applicability::MaybeIncorrect,
         );
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 3539202d1ca6f..3f3323cc1af04 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,9 +1,10 @@
 use super::FnCtxt;
 
 use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
+use crate::fluent_generated as fluent;
 use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
-use rustc_errors::{fluent, Applicability, Diagnostic, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 0204beb6fb84d..57c6c155a4dba 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -53,7 +53,10 @@ use crate::check::check_fn;
 use crate::coercion::DynamicCoerceMany;
 use crate::gather_locals::GatherLocalsVisitor;
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{
+    struct_span_err, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
+    SubdiagnosticMessage,
+};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::Visitor;
@@ -61,6 +64,7 @@ use rustc_hir::{HirIdMap, Node};
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_hir_analysis::check::check_abi;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_macros::fluent_messages;
 use rustc_middle::traits;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -69,6 +73,8 @@ use rustc_session::Session;
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 #[macro_export]
 macro_rules! type_error_struct {
     ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
diff --git a/compiler/rustc_error_messages/locales/en-US/incremental.ftl b/compiler/rustc_incremental/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/incremental.ftl
rename to compiler/rustc_incremental/locales/en-US.ftl
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 3c58cfa38f280..511e466c2aeb1 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -31,3 +31,8 @@ pub use persist::save_dep_graph;
 pub use persist::save_work_product_index;
 pub use persist::LoadResult;
 pub use persist::{build_dep_graph, load_dep_graph, DepGraphFuture};
+
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_infer/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/infer.ftl
rename to compiler/rustc_infer/locales/en-US.ftl
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 0c2713fb1a7c8..7dccd0bb930c3 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1,6 +1,6 @@
 use hir::GenericParamKind;
 use rustc_errors::{
-    fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
+    AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
     IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage,
 };
 use rustc_hir as hir;
@@ -12,9 +12,10 @@ use rustc_span::symbol::kw;
 use rustc_span::Symbol;
 use rustc_span::{symbol::Ident, BytePos, Span};
 
-use crate::infer::error_reporting::nice_region_error::placeholder_error::Highlighted;
+use crate::fluent_generated as fluent;
 use crate::infer::error_reporting::{
     need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
+    nice_region_error::placeholder_error::Highlighted,
     ObligationCauseAsDiagArg,
 };
 
@@ -26,9 +27,9 @@ pub struct OpaqueHiddenTypeDiag {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[note(opaque_type)]
+    #[note(infer_opaque_type)]
     pub opaque_type: Span,
-    #[note(hidden_type)]
+    #[note(infer_hidden_type)]
     pub hidden_type: Span,
 }
 
@@ -768,11 +769,11 @@ impl<'tcx> ActualImplExplNotes<'tcx> {
 pub struct TraitPlaceholderMismatch<'tcx> {
     #[primary_span]
     pub span: Span,
-    #[label(label_satisfy)]
+    #[label(infer_label_satisfy)]
     pub satisfy_span: Option<Span>,
-    #[label(label_where)]
+    #[label(infer_label_where)]
     pub where_span: Option<Span>,
-    #[label(label_dup)]
+    #[label(infer_label_dup)]
     pub dup_span: Option<Span>,
     pub def_id: String,
     pub trait_def_id: String,
@@ -808,11 +809,11 @@ pub struct RelationshipHelp;
 #[diag(infer_trait_impl_diff)]
 pub struct TraitImplDiff {
     #[primary_span]
-    #[label(found)]
+    #[label(infer_found)]
     pub sp: Span,
-    #[label(expected)]
+    #[label(infer_expected)]
     pub trait_sp: Span,
-    #[note(expected_found)]
+    #[note(infer_expected_found)]
     pub note: (),
     #[subdiagnostic]
     pub param_help: ConsiderBorrowingParamHelp,
@@ -852,10 +853,10 @@ impl AddToDiagnostic for DynTraitConstraintSuggestion {
 #[derive(Diagnostic)]
 #[diag(infer_but_calling_introduces, code = "E0772")]
 pub struct ButCallingIntroduces {
-    #[label(label1)]
+    #[label(infer_label1)]
     pub param_ty_span: Span,
     #[primary_span]
-    #[label(label2)]
+    #[label(infer_label2)]
     pub cause_span: Span,
 
     pub has_param_name: bool,
@@ -913,15 +914,15 @@ impl AddToDiagnostic for MoreTargeted {
 pub struct ButNeedsToSatisfy {
     #[primary_span]
     pub sp: Span,
-    #[label(influencer)]
+    #[label(infer_influencer)]
     pub influencer_point: Span,
-    #[label(used_here)]
+    #[label(infer_used_here)]
     pub spans: Vec<Span>,
-    #[label(require)]
+    #[label(infer_require)]
     pub require_span_as_label: Option<Span>,
-    #[note(require)]
+    #[note(infer_require)]
     pub require_span_as_note: Option<Span>,
-    #[note(introduced_by_bound)]
+    #[note(infer_introduced_by_bound)]
     pub bound: Option<Span>,
 
     #[subdiagnostic]
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index cb96aeec5f34f..ef543b1fb9353 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -1,7 +1,6 @@
+use crate::fluent_generated as fluent;
 use crate::infer::error_reporting::nice_region_error::find_anon_type;
-use rustc_errors::{
-    self, fluent, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage,
-};
+use rustc_errors::{self, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{symbol::kw, Span};
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index e0e89158a5838..7ffe1fd20b49a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -2,10 +2,11 @@ use crate::errors::{
     note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
     RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
 };
+use crate::fluent_generated as fluent;
 use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
 use crate::infer::{self, SubregionOrigin};
 use rustc_errors::{
-    fluent, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
+    AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
 };
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::traits::ObligationCauseCode;
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 4c119a443555e..b03ecb5975080 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -33,6 +33,11 @@ extern crate tracing;
 #[macro_use]
 extern crate rustc_middle;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 mod errors;
 pub mod infer;
 pub mod traits;
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_error_messages/locales/en-US/interface.ftl b/compiler/rustc_interface/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/interface.ftl
rename to compiler/rustc_interface/locales/en-US.ftl
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index d504aea77d0da..5e38ca034ac1f 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -222,6 +222,7 @@ pub struct Config {
     pub output_dir: Option<PathBuf>,
     pub output_file: Option<PathBuf>,
     pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    pub locale_resources: &'static [&'static str],
 
     pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
 
@@ -267,6 +268,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 config.opts,
                 config.crate_cfg,
                 config.crate_check_cfg,
+                config.locale_resources,
                 config.file_loader,
                 CompilerIO {
                     input: config.input,
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 82bc4770b6b47..1abbe8d4fabef 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -12,6 +12,9 @@
 #[macro_use]
 extern crate tracing;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 mod callbacks;
 mod errors;
 pub mod interface;
@@ -27,3 +30,5 @@ pub use queries::Queries;
 
 #[cfg(test)]
 mod tests;
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index bfb1e822a2697..71a72036994d2 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -50,7 +50,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
         output_file: None,
         temps_dir,
     };
-    let sess = build_session(sessopts, io, None, registry, Default::default(), None, None);
+    let sess = build_session(sessopts, io, None, registry, vec![], Default::default(), None, None);
     (sess, cfg)
 }
 
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 475d3601b52ab..e5d2fb2ea2807 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -59,6 +59,7 @@ pub fn create_session(
     sopts: config::Options,
     cfg: FxHashSet<(String, Option<String>)>,
     check_cfg: CheckCfg,
+    locale_resources: &'static [&'static str],
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     io: CompilerIO,
     lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -89,11 +90,15 @@ pub fn create_session(
         }
     };
 
+    let mut locale_resources = Vec::from(locale_resources);
+    locale_resources.push(codegen_backend.locale_resource());
+
     let mut sess = session::build_session(
         sopts,
         io,
         bundle,
         descriptions,
+        locale_resources,
         lint_caps,
         file_loader,
         target_override,
diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_lint/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/lint.ftl
rename to compiler/rustc_lint/locales/en-US.ftl
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index 3593f141df61b..bccb0a94e986d 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -1,5 +1,7 @@
-use crate::lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub};
-use crate::{LateContext, LateLintPass, LintContext};
+use crate::{
+    lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub},
+    LateContext, LateLintPass, LintContext,
+};
 use rustc_hir as hir;
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 726042479e9b0..5e90669d33a4a 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -20,6 +20,7 @@
 //! If you define a new `LateLintPass`, you will also need to add it to the
 //! `late_lint_methods!` invocation in `lib.rs`.
 
+use crate::fluent_generated as fluent;
 use crate::{
     errors::BuiltinEllpisisInclusiveRangePatterns,
     lints::{
@@ -50,7 +51,7 @@ use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{fluent, Applicability, DecorateLint, MultiSpan};
+use rustc_errors::{Applicability, DecorateLint, MultiSpan};
 use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index f3ae26091863d..9af5284df1e29 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -1,6 +1,6 @@
+use crate::fluent_generated as fluent;
 use rustc_errors::{
-    fluent, AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic,
-    SubdiagnosticMessage,
+    AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic, SubdiagnosticMessage,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::lint::Level;
@@ -116,7 +116,7 @@ impl IntoDiagnostic<'_> for CheckNameUnknown {
         let mut diag = handler.struct_err(fluent::lint_check_name_unknown);
         diag.code(rustc_errors::error_code!(E0602));
         if let Some(suggestion) = self.suggestion {
-            diag.help(fluent::help);
+            diag.help(fluent::lint_help);
             diag.set_arg("suggestion", suggestion);
         }
         diag.set_arg("lint_name", self.lint_name);
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index cca36913dea11..bc7488fab4a5c 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,13 +1,16 @@
-use crate::context::{CheckLintNameResult, LintStore};
-use crate::late::unerased_lint_store;
-use crate::lints::{
-    DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, RenamedOrRemovedLint,
-    RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion,
+use crate::{
+    context::{CheckLintNameResult, LintStore},
+    fluent_generated as fluent,
+    late::unerased_lint_store,
+    lints::{
+        DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint,
+        RenamedOrRemovedLint, RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion,
+    },
 };
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{fluent, DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
+use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::HirId;
@@ -983,7 +986,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     fluent::lint_unknown_gated_lint,
                     |lint| {
                         lint.set_arg("name", lint_id.lint.name_lower());
-                        lint.note(fluent::note);
+                        lint.note(fluent::lint_note);
                         add_feature_diagnostics(lint, &self.sess.parse_sess, feature);
                         lint
                     },
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 4ca37ef6850c1..2070ffea4d99e 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -80,8 +80,10 @@ mod unused;
 pub use array_into_iter::ARRAY_INTO_ITER;
 
 use rustc_ast as ast;
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
+use rustc_macros::fluent_messages;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
@@ -122,6 +124,8 @@ pub use rustc_session::lint::Level::{self, *};
 pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
 pub use rustc_session::lint::{LintArray, LintPass};
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub fn provide(providers: &mut Providers) {
     levels::provide(providers);
     expect::provide(providers);
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index aa6e230dc6d6d..2d9aa9074be79 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -2,9 +2,10 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 use std::num::NonZeroU32;
 
+use crate::fluent_generated as fluent;
 use rustc_errors::{
-    fluent, AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage,
-    DiagnosticStyledString, SuggestionStyle,
+    AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString,
+    SuggestionStyle,
 };
 use rustc_hir::def_id::DefId;
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
@@ -23,7 +24,7 @@ use crate::{
 #[diag(lint_array_into_iter)]
 pub struct ArrayIntoIterDiag<'a> {
     pub target: &'a str,
-    #[suggestion(use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
+    #[suggestion(lint_use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
     pub suggestion: Span,
     #[subdiagnostic]
     pub sub: Option<ArrayIntoIterDiagSub>,
@@ -31,12 +32,15 @@ pub struct ArrayIntoIterDiag<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum ArrayIntoIterDiagSub {
-    #[suggestion(remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
+    #[suggestion(lint_remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
     RemoveIntoIter {
         #[primary_span]
         span: Span,
     },
-    #[multipart_suggestion(use_explicit_into_iter_suggestion, applicability = "maybe-incorrect")]
+    #[multipart_suggestion(
+        lint_use_explicit_into_iter_suggestion,
+        applicability = "maybe-incorrect"
+    )]
     UseExplicitIntoIter {
         #[suggestion_part(code = "IntoIterator::into_iter(")]
         start_span: Span,
@@ -163,13 +167,13 @@ pub struct BuiltinDeprecatedAttrLink<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum BuiltinDeprecatedAttrLinkSuggestion<'a> {
-    #[suggestion(msg_suggestion, code = "", applicability = "machine-applicable")]
+    #[suggestion(lint_msg_suggestion, code = "", applicability = "machine-applicable")]
     Msg {
         #[primary_span]
         suggestion: Span,
         msg: &'a str,
     },
-    #[suggestion(default_suggestion, code = "", applicability = "machine-applicable")]
+    #[suggestion(lint_default_suggestion, code = "", applicability = "machine-applicable")]
     Default {
         #[primary_span]
         suggestion: Span,
@@ -201,9 +205,9 @@ pub struct BuiltinUnusedDocComment<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum BuiltinUnusedDocCommentSub {
-    #[help(plain_help)]
+    #[help(lint_plain_help)]
     PlainHelp,
-    #[help(block_help)]
+    #[help(lint_block_help)]
     BlockHelp,
 }
 
@@ -242,7 +246,7 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
         self,
         diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
-        diag.span_label(self.label, fluent::label);
+        diag.span_label(self.label, fluent::lint_label);
         rustc_session::parse::add_feature_diagnostics(
             diag,
             &self.parse_sess,
@@ -337,7 +341,7 @@ impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
         ) -> rustc_errors::SubdiagnosticMessage,
     {
         diag.multipart_suggestion(
-            fluent::suggestion,
+            fluent::lint_suggestion,
             self.suggestions,
             Applicability::MachineApplicable,
         );
@@ -388,7 +392,7 @@ pub struct BuiltinExplicitOutlives {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion)]
+#[multipart_suggestion(lint_suggestion)]
 pub struct BuiltinExplicitOutlivesSuggestion {
     #[suggestion_part(code = "")]
     pub spans: Vec<Span>,
@@ -407,11 +411,11 @@ pub struct BuiltinIncompleteFeatures {
 }
 
 #[derive(Subdiagnostic)]
-#[help(help)]
+#[help(lint_help)]
 pub struct BuiltinIncompleteFeaturesHelp;
 
 #[derive(Subdiagnostic)]
-#[note(note)]
+#[note(lint_note)]
 pub struct BuiltinIncompleteFeaturesNote {
     pub n: NonZeroU32,
 }
@@ -482,9 +486,9 @@ pub enum BuiltinClashingExtern<'a> {
     SameName {
         this: Symbol,
         orig: Symbol,
-        #[label(previous_decl_label)]
+        #[label(lint_previous_decl_label)]
         previous_decl_label: Span,
-        #[label(mismatch_label)]
+        #[label(lint_mismatch_label)]
         mismatch_label: Span,
         #[subdiagnostic]
         sub: BuiltinClashingExternSub<'a>,
@@ -493,9 +497,9 @@ pub enum BuiltinClashingExtern<'a> {
     DiffName {
         this: Symbol,
         orig: Symbol,
-        #[label(previous_decl_label)]
+        #[label(lint_previous_decl_label)]
         previous_decl_label: Span,
-        #[label(mismatch_label)]
+        #[label(lint_mismatch_label)]
         mismatch_label: Span,
         #[subdiagnostic]
         sub: BuiltinClashingExternSub<'a>,
@@ -571,7 +575,7 @@ pub struct SupertraitAsDerefTarget<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[label(label)]
+#[label(lint_label)]
 pub struct SupertraitAsDerefTargetLabel {
     #[primary_span]
     pub label: Span,
@@ -604,7 +608,7 @@ pub struct Expectation {
 }
 
 #[derive(Subdiagnostic)]
-#[note(rationale)]
+#[note(lint_rationale)]
 pub struct ExpectationNote {
     pub rationale: Symbol,
 }
@@ -625,13 +629,13 @@ pub struct ForLoopsOverFalliblesDiag<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum ForLoopsOverFalliblesLoopSub<'a> {
-    #[suggestion(remove_next, code = ".by_ref()", applicability = "maybe-incorrect")]
+    #[suggestion(lint_remove_next, code = ".by_ref()", applicability = "maybe-incorrect")]
     RemoveNext {
         #[primary_span]
         suggestion: Span,
         recv_snip: String,
     },
-    #[multipart_suggestion(use_while_let, applicability = "maybe-incorrect")]
+    #[multipart_suggestion(lint_use_while_let, applicability = "maybe-incorrect")]
     UseWhileLet {
         #[suggestion_part(code = "while let {var}(")]
         start_span: Span,
@@ -642,14 +646,14 @@ pub enum ForLoopsOverFalliblesLoopSub<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(use_question_mark, code = "?", applicability = "maybe-incorrect")]
+#[suggestion(lint_use_question_mark, code = "?", applicability = "maybe-incorrect")]
 pub struct ForLoopsOverFalliblesQuestionMark {
     #[primary_span]
     pub suggestion: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
+#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")]
 pub struct ForLoopsOverFalliblesSuggestion<'a> {
     pub var: &'a str,
     #[suggestion_part(code = "if let {var}(")]
@@ -708,13 +712,13 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub {
         match self {
             HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
                 diag.multipart_suggestion_with_style(
-                    fluent::suggestion_remove,
+                    fluent::lint_suggestion_remove,
                     spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
                     Applicability::MachineApplicable,
                     SuggestionStyle::HideCodeAlways,
                 );
                 diag.multipart_suggestion(
-                    fluent::suggestion_escape,
+                    fluent::lint_suggestion_escape,
                     spans
                         .into_iter()
                         .map(|(c, span)| {
@@ -737,8 +741,8 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub {
                         .collect::<Vec<String>>()
                         .join(", "),
                 );
-                diag.note(fluent::suggestion_remove);
-                diag.note(fluent::no_suggestion_note_escape);
+                diag.note(fluent::lint_suggestion_remove);
+                diag.note(fluent::lint_no_suggestion_note_escape);
             }
         }
     }
@@ -883,7 +887,7 @@ pub struct RenamedOrRemovedLint<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(suggestion, code = "{replace}", applicability = "machine-applicable")]
+#[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")]
 pub struct RenamedOrRemovedLintSuggestion<'a> {
     #[primary_span]
     pub suggestion: Span,
@@ -899,7 +903,7 @@ pub struct UnknownLint {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+#[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
 pub struct UnknownLintSuggestion {
     #[primary_span]
     pub suggestion: Span,
@@ -919,9 +923,9 @@ pub struct IgnoredUnlessCrateSpecified<'a> {
 #[note]
 #[help]
 pub struct CStringPtr {
-    #[label(as_ptr_label)]
+    #[label(lint_as_ptr_label)]
     pub as_ptr: Span,
-    #[label(unwrap_label)]
+    #[label(lint_unwrap_label)]
     pub unwrap: Span,
 }
 
@@ -952,7 +956,7 @@ pub struct ConfusableIdentifierPair {
 
 #[derive(LintDiagnostic)]
 #[diag(lint_mixed_script_confusables)]
-#[note(includes_note)]
+#[note(lint_includes_note)]
 #[note]
 pub struct MixedScriptConfusables {
     pub set: String,
@@ -972,17 +976,17 @@ impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
         diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
         diag.set_arg("count", self.count);
-        diag.note(fluent::note);
+        diag.note(fluent::lint_note);
         if let Some(span) = self.suggestion {
             diag.span_suggestion(
                 span.shrink_to_hi(),
-                fluent::add_args_suggestion,
+                fluent::lint_add_args_suggestion,
                 ", ...",
                 Applicability::HasPlaceholders,
             );
             diag.span_suggestion(
                 span.shrink_to_lo(),
-                fluent::add_fmt_suggestion,
+                fluent::lint_add_fmt_suggestion,
                 "\"{}\", ",
                 Applicability::MachineApplicable,
             );
@@ -1016,12 +1020,12 @@ pub struct NonCamelCaseType<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum NonCamelCaseTypeSub {
-    #[label(label)]
+    #[label(lint_label)]
     Label {
         #[primary_span]
         span: Span,
     },
-    #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+    #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
     Suggestion {
         #[primary_span]
         span: Span,
@@ -1057,15 +1061,15 @@ impl AddToDiagnostic for NonSnakeCaseDiagSub {
     {
         match self {
             NonSnakeCaseDiagSub::Label { span } => {
-                diag.span_label(span, fluent::label);
+                diag.span_label(span, fluent::lint_label);
             }
             NonSnakeCaseDiagSub::Help => {
-                diag.help(fluent::help);
+                diag.help(fluent::lint_help);
             }
             NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => {
                 diag.span_suggestion(
                     span,
-                    fluent::convert_suggestion,
+                    fluent::lint_convert_suggestion,
                     suggestion,
                     Applicability::MaybeIncorrect,
                 );
@@ -1073,16 +1077,16 @@ impl AddToDiagnostic for NonSnakeCaseDiagSub {
             NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, suggestion } => {
                 diag.span_suggestion(
                     span,
-                    fluent::rename_or_convert_suggestion,
+                    fluent::lint_rename_or_convert_suggestion,
                     suggestion,
                     Applicability::MaybeIncorrect,
                 );
             }
             NonSnakeCaseDiagSub::SuggestionAndNote { span } => {
-                diag.note(fluent::cannot_convert_note);
+                diag.note(fluent::lint_cannot_convert_note);
                 diag.span_suggestion(
                     span,
-                    fluent::rename_suggestion,
+                    fluent::lint_rename_suggestion,
                     "",
                     Applicability::MaybeIncorrect,
                 );
@@ -1102,12 +1106,12 @@ pub struct NonUpperCaseGlobal<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum NonUpperCaseGlobalSub {
-    #[label(label)]
+    #[label(lint_label)]
     Label {
         #[primary_span]
         span: Span,
     },
-    #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
+    #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")]
     Suggestion {
         #[primary_span]
         span: Span,
@@ -1225,11 +1229,11 @@ impl AddToDiagnostic for OverflowingBinHexSign {
     {
         match self {
             OverflowingBinHexSign::Positive => {
-                diag.note(fluent::positive_note);
+                diag.note(fluent::lint_positive_note);
             }
             OverflowingBinHexSign::Negative => {
-                diag.note(fluent::negative_note);
-                diag.note(fluent::negative_becomes_note);
+                diag.note(fluent::lint_negative_note);
+                diag.note(fluent::lint_negative_becomes_note);
             }
         }
     }
@@ -1238,7 +1242,7 @@ impl AddToDiagnostic for OverflowingBinHexSign {
 #[derive(Subdiagnostic)]
 pub enum OverflowingBinHexSub<'a> {
     #[suggestion(
-        suggestion,
+        lint_suggestion,
         code = "{sans_suffix}{suggestion_ty}",
         applicability = "machine-applicable"
     )]
@@ -1248,7 +1252,7 @@ pub enum OverflowingBinHexSub<'a> {
         suggestion_ty: &'a str,
         sans_suffix: &'a str,
     },
-    #[help(help)]
+    #[help(lint_help)]
     Help { suggestion_ty: &'a str },
 }
 
@@ -1265,7 +1269,7 @@ pub struct OverflowingInt<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[help(help)]
+#[help(lint_help)]
 pub struct OverflowingIntHelp<'a> {
     pub suggestion_ty: &'a str,
 }
@@ -1317,13 +1321,13 @@ impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> {
     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
         diag.set_arg("ty", self.ty);
         diag.set_arg("desc", self.desc);
-        diag.span_label(self.label, fluent::label);
+        diag.span_label(self.label, fluent::lint_label);
         if let Some(help) = self.help {
             diag.help(help);
         }
         diag.note(self.note);
         if let Some(note) = self.span_note {
-            diag.span_note(note, fluent::note);
+            diag.span_note(note, fluent::lint_note);
         }
         diag
     }
@@ -1416,7 +1420,7 @@ pub struct UnusedDef<'a, 'b> {
 #[derive(Subdiagnostic)]
 pub enum UnusedDefSuggestion {
     #[suggestion(
-        suggestion,
+        lint_suggestion,
         style = "verbose",
         code = "let _ = ",
         applicability = "machine-applicable"
@@ -1460,13 +1464,13 @@ pub struct PathStatementDrop {
 
 #[derive(Subdiagnostic)]
 pub enum PathStatementDropSub {
-    #[suggestion(suggestion, code = "drop({snippet});", applicability = "machine-applicable")]
+    #[suggestion(lint_suggestion, code = "drop({snippet});", applicability = "machine-applicable")]
     Suggestion {
         #[primary_span]
         span: Span,
         snippet: String,
     },
-    #[help(help)]
+    #[help(lint_help)]
     Help {
         #[primary_span]
         span: Span,
@@ -1487,7 +1491,7 @@ pub struct UnusedDelim<'a> {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
 pub struct UnusedDelimSuggestion {
     #[suggestion_part(code = "{start_replace}")]
     pub start_span: Span,
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 548f30ec97264..5bb1abfd2ec97 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -1,7 +1,7 @@
 use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused};
-use crate::{LateContext, LateLintPass, LintContext};
+use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
-use rustc_errors::{fluent, Applicability};
+use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::lint::in_external_macro;
@@ -122,18 +122,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
     #[allow(rustc::diagnostic_outside_of_impl)]
     cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| {
         lint.set_arg("name", symbol);
-        lint.note(fluent::note);
-        lint.note(fluent::more_info_note);
+        lint.note(fluent::lint_note);
+        lint.note(fluent::lint_more_info_note);
         if !is_arg_inside_call(arg_span, span) {
             // No clue where this argument is coming from.
             return lint;
         }
         if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
             // A case of `panic!(format!(..))`.
-            lint.note(fluent::supports_fmt_note);
+            lint.note(fluent::lint_supports_fmt_note);
             if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
                 lint.multipart_suggestion(
-                    fluent::supports_fmt_suggestion,
+                    fluent::lint_supports_fmt_suggestion,
                     vec![
                         (arg_span.until(open.shrink_to_hi()), "".into()),
                         (close.until(arg_span.shrink_to_hi()), "".into()),
@@ -179,7 +179,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
             if suggest_display {
                 lint.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
-                    fluent::display_suggestion,
+                    fluent::lint_display_suggestion,
                     "\"{}\", ",
                     fmt_applicability,
                 );
@@ -187,7 +187,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 lint.set_arg("ty", ty);
                 lint.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
-                    fluent::debug_suggestion,
+                    fluent::lint_debug_suggestion,
                     "\"{:?}\", ",
                     fmt_applicability,
                 );
@@ -197,7 +197,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 if let Some((open, close, del)) = find_delimiters(cx, span) {
                     lint.set_arg("already_suggested", suggest_display || suggest_debug);
                     lint.multipart_suggestion(
-                        fluent::panic_suggestion,
+                        fluent::lint_panic_suggestion,
                         if del == '(' {
                             vec![(span.until(open), "std::panic::panic_any".into())]
                         } else {
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 42442cfb1904d..883a56cb3ce6b 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
 struct OpaqueHiddenInferredBoundLint<'tcx> {
     ty: Ty<'tcx>,
     proj_ty: Ty<'tcx>,
-    #[label(specifically)]
+    #[label(lint_specifically)]
     assoc_pred_span: Span,
     #[subdiagnostic]
     add_bound: Option<AddBound<'tcx>>,
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index b7fd6a254d811..a7f2e9f6eb150 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1,14 +1,17 @@
-use crate::lints::{
-    AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
-    InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign,
-    OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt,
-    RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag,
+use crate::{
+    fluent_generated as fluent,
+    lints::{
+        AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
+        InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign,
+        OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral,
+        OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag,
+    },
 };
 use crate::{LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{fluent, DiagnosticMessage};
+use rustc_errors::DiagnosticMessage;
 use rustc_hir as hir;
 use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 9ff9448640477..12a954258d1de 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -57,7 +57,7 @@ impl<'a> DiagnosticDerive<'a> {
                 }
                 Some(slug) => {
                     quote! {
-                        let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
+                        let mut #diag = #handler.struct_diagnostic(crate::fluent_generated::#slug);
                     }
                 }
             };
@@ -149,7 +149,7 @@ impl<'a> LintDiagnosticDerive<'a> {
                 }
                 Some(slug) => {
                     quote! {
-                        rustc_errors::fluent::#slug.into()
+                        crate::fluent_generated::#slug.into()
                     }
                 }
             }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 12bcd939bd61b..46068f8c868cd 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -452,7 +452,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
                 Ok(quote! {
                     #diag.span_suggestions_with_style(
                         #span_field,
-                        rustc_errors::fluent::#slug,
+                        crate::fluent_generated::#slug,
                         #code_field,
                         #applicability,
                         #style
@@ -476,7 +476,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
         quote! {
             #diag.#fn_name(
                 #field_binding,
-                rustc_errors::fluent::#fluent_attr_identifier
+                crate::fluent_generated::#fluent_attr_identifier
             );
         }
     }
@@ -486,7 +486,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
     fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream {
         let diag = &self.parent.diag;
         quote! {
-            #diag.#kind(rustc_errors::fluent::#fluent_attr_identifier);
+            #diag.#kind(crate::fluent_generated::#fluent_attr_identifier);
         }
     }
 
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index 08098c9bb2a85..38c0f4895db06 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -19,52 +19,9 @@ use std::{
     io::Read,
     path::{Path, PathBuf},
 };
-use syn::{
-    parse::{Parse, ParseStream},
-    parse_macro_input,
-    punctuated::Punctuated,
-    token, Ident, LitStr, Result,
-};
+use syn::{parse_macro_input, Ident, LitStr};
 use unic_langid::langid;
 
-struct Resource {
-    krate: Ident,
-    #[allow(dead_code)]
-    fat_arrow_token: token::FatArrow,
-    resource_path: LitStr,
-}
-
-impl Parse for Resource {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        Ok(Resource {
-            krate: input.parse()?,
-            fat_arrow_token: input.parse()?,
-            resource_path: input.parse()?,
-        })
-    }
-}
-
-struct Resources(Punctuated<Resource, token::Comma>);
-
-impl Parse for Resources {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        let mut resources = Punctuated::new();
-        loop {
-            if input.is_empty() || input.peek(token::Brace) {
-                break;
-            }
-            let value = input.parse()?;
-            resources.push_value(value);
-            if !input.peek(token::Comma) {
-                break;
-            }
-            let punct = input.parse()?;
-            resources.push_punct(punct);
-        }
-        Ok(Resources(resources))
-    }
-}
-
 /// Helper function for returning an absolute path for macro-invocation relative file paths.
 ///
 /// If the input is already absolute, then the input is returned. If the input is not absolute,
@@ -84,251 +41,285 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf {
     }
 }
 
+/// Tokens to be returned when the macro cannot proceed.
+fn failed(crate_name: &Ident) -> proc_macro::TokenStream {
+    quote! {
+        pub static DEFAULT_LOCALE_RESOURCE: &'static str = "";
+
+        #[allow(non_upper_case_globals)]
+        #[doc(hidden)]
+        pub(crate) mod fluent_generated {
+            pub mod #crate_name {
+            }
+
+            pub mod _subdiag {
+                pub const help: crate::SubdiagnosticMessage =
+                    crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help"));
+                pub const note: crate::SubdiagnosticMessage =
+                    crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
+                pub const warn: crate::SubdiagnosticMessage =
+                    crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn"));
+                pub const label: crate::SubdiagnosticMessage =
+                    crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label"));
+                pub const suggestion: crate::SubdiagnosticMessage =
+                    crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion"));
+            }
+        }
+    }
+    .into()
+}
+
 /// See [rustc_macros::fluent_messages].
 pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
-    let resources = parse_macro_input!(input as Resources);
+    let crate_name = std::env::var("CARGO_PKG_NAME")
+        // If `CARGO_PKG_NAME` is missing, then we're probably running in a test, so use
+        // `no_crate`.
+        .unwrap_or_else(|_| "no_crate".to_string())
+        .replace("rustc_", "");
 
     // Cannot iterate over individual messages in a bundle, so do that using the
     // `FluentResource` instead. Construct a bundle anyway to find out if there are conflicting
     // messages in the resources.
     let mut bundle = FluentBundle::new(vec![langid!("en-US")]);
 
-    // Map of Fluent identifiers to the `Span` of the resource that defined them, used for better
-    // diagnostics.
-    let mut previous_defns = HashMap::new();
-
     // Set of Fluent attribute names already output, to avoid duplicate type errors - any given
     // constant created for a given attribute is the same.
     let mut previous_attrs = HashSet::new();
 
-    let mut includes = TokenStream::new();
-    let mut generated = TokenStream::new();
+    let resource_str = parse_macro_input!(input as LitStr);
+    let resource_span = resource_str.span().unwrap();
+    let relative_ftl_path = resource_str.value();
+    let absolute_ftl_path = invocation_relative_path_to_absolute(resource_span, &relative_ftl_path);
 
-    for res in resources.0 {
-        let krate_span = res.krate.span().unwrap();
-        let path_span = res.resource_path.span().unwrap();
+    let crate_name = Ident::new(&crate_name, resource_str.span());
 
-        let relative_ftl_path = res.resource_path.value();
-        let absolute_ftl_path =
-            invocation_relative_path_to_absolute(krate_span, &relative_ftl_path);
-        // As this macro also outputs an `include_str!` for this file, the macro will always be
-        // re-executed when the file changes.
-        let mut resource_file = match File::open(absolute_ftl_path) {
-            Ok(resource_file) => resource_file,
-            Err(e) => {
-                Diagnostic::spanned(path_span, Level::Error, "could not open Fluent resource")
-                    .note(e.to_string())
-                    .emit();
-                continue;
-            }
-        };
-        let mut resource_contents = String::new();
-        if let Err(e) = resource_file.read_to_string(&mut resource_contents) {
-            Diagnostic::spanned(path_span, Level::Error, "could not read Fluent resource")
+    // As this macro also outputs an `include_str!` for this file, the macro will always be
+    // re-executed when the file changes.
+    let mut resource_file = match File::open(absolute_ftl_path) {
+        Ok(resource_file) => resource_file,
+        Err(e) => {
+            Diagnostic::spanned(resource_span, Level::Error, "could not open Fluent resource")
                 .note(e.to_string())
                 .emit();
-            continue;
+            return failed(&crate_name);
         }
-        let resource = match FluentResource::try_new(resource_contents) {
-            Ok(resource) => resource,
-            Err((this, errs)) => {
-                Diagnostic::spanned(path_span, Level::Error, "could not parse Fluent resource")
-                    .help("see additional errors emitted")
-                    .emit();
-                for ParserError { pos, slice: _, kind } in errs {
-                    let mut err = kind.to_string();
-                    // Entirely unnecessary string modification so that the error message starts
-                    // with a lowercase as rustc errors do.
-                    err.replace_range(
-                        0..1,
-                        &err.chars().next().unwrap().to_lowercase().to_string(),
-                    );
+    };
+    let mut resource_contents = String::new();
+    if let Err(e) = resource_file.read_to_string(&mut resource_contents) {
+        Diagnostic::spanned(resource_span, Level::Error, "could not read Fluent resource")
+            .note(e.to_string())
+            .emit();
+        return failed(&crate_name);
+    }
+
+    let resource = match FluentResource::try_new(resource_contents) {
+        Ok(resource) => resource,
+        Err((this, errs)) => {
+            Diagnostic::spanned(resource_span, Level::Error, "could not parse Fluent resource")
+                .help("see additional errors emitted")
+                .emit();
+            for ParserError { pos, slice: _, kind } in errs {
+                let mut err = kind.to_string();
+                // Entirely unnecessary string modification so that the error message starts
+                // with a lowercase as rustc errors do.
+                err.replace_range(0..1, &err.chars().next().unwrap().to_lowercase().to_string());
 
-                    let line_starts: Vec<usize> = std::iter::once(0)
-                        .chain(
-                            this.source()
-                                .char_indices()
-                                .filter_map(|(i, c)| Some(i + 1).filter(|_| c == '\n')),
-                        )
-                        .collect();
-                    let line_start = line_starts
-                        .iter()
-                        .enumerate()
-                        .map(|(line, idx)| (line + 1, idx))
-                        .filter(|(_, idx)| **idx <= pos.start)
-                        .last()
-                        .unwrap()
-                        .0;
+                let line_starts: Vec<usize> = std::iter::once(0)
+                    .chain(
+                        this.source()
+                            .char_indices()
+                            .filter_map(|(i, c)| Some(i + 1).filter(|_| c == '\n')),
+                    )
+                    .collect();
+                let line_start = line_starts
+                    .iter()
+                    .enumerate()
+                    .map(|(line, idx)| (line + 1, idx))
+                    .filter(|(_, idx)| **idx <= pos.start)
+                    .last()
+                    .unwrap()
+                    .0;
 
-                    let snippet = Snippet {
-                        title: Some(Annotation {
-                            label: Some(&err),
-                            id: None,
+                let snippet = Snippet {
+                    title: Some(Annotation {
+                        label: Some(&err),
+                        id: None,
+                        annotation_type: AnnotationType::Error,
+                    }),
+                    footer: vec![],
+                    slices: vec![Slice {
+                        source: this.source(),
+                        line_start,
+                        origin: Some(&relative_ftl_path),
+                        fold: true,
+                        annotations: vec![SourceAnnotation {
+                            label: "",
                             annotation_type: AnnotationType::Error,
-                        }),
-                        footer: vec![],
-                        slices: vec![Slice {
-                            source: this.source(),
-                            line_start,
-                            origin: Some(&relative_ftl_path),
-                            fold: true,
-                            annotations: vec![SourceAnnotation {
-                                label: "",
-                                annotation_type: AnnotationType::Error,
-                                range: (pos.start, pos.end - 1),
-                            }],
+                            range: (pos.start, pos.end - 1),
                         }],
-                        opt: Default::default(),
-                    };
-                    let dl = DisplayList::from(snippet);
-                    eprintln!("{dl}\n");
-                }
-                continue;
+                    }],
+                    opt: Default::default(),
+                };
+                let dl = DisplayList::from(snippet);
+                eprintln!("{dl}\n");
             }
-        };
 
-        let mut constants = TokenStream::new();
-        let mut messagerefs = Vec::new();
-        for entry in resource.entries() {
-            let span = res.krate.span();
-            if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) =
-                entry
-            {
-                let _ = previous_defns.entry(name.to_string()).or_insert(path_span);
+            return failed(&crate_name);
+        }
+    };
 
-                if name.contains('-') {
-                    Diagnostic::spanned(
-                        path_span,
-                        Level::Error,
-                        format!("name `{name}` contains a '-' character"),
-                    )
-                    .help("replace any '-'s with '_'s")
-                    .emit();
-                }
+    let mut constants = TokenStream::new();
+    let mut previous_defns = HashMap::new();
+    let mut message_refs = Vec::new();
+    for entry in resource.entries() {
+        if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) = entry {
+            let _ = previous_defns.entry(name.to_string()).or_insert(resource_span);
+            if name.contains('-') {
+                Diagnostic::spanned(
+                    resource_span,
+                    Level::Error,
+                    format!("name `{name}` contains a '-' character"),
+                )
+                .help("replace any '-'s with '_'s")
+                .emit();
+            }
 
-                if let Some(Pattern { elements }) = value {
-                    for elt in elements {
-                        if let PatternElement::Placeable {
-                            expression:
-                                Expression::Inline(InlineExpression::MessageReference { id, .. }),
-                        } = elt
-                        {
-                            messagerefs.push((id.name, *name));
-                        }
+            if let Some(Pattern { elements }) = value {
+                for elt in elements {
+                    if let PatternElement::Placeable {
+                        expression:
+                            Expression::Inline(InlineExpression::MessageReference { id, .. }),
+                    } = elt
+                    {
+                        message_refs.push((id.name, *name));
                     }
                 }
+            }
 
-                // Require that the message name starts with the crate name
-                // `hir_typeck_foo_bar` (in `hir_typeck.ftl`)
-                // `const_eval_baz` (in `const_eval.ftl`)
-                // `const-eval-hyphen-having` => `hyphen_having` (in `const_eval.ftl`)
-                // The last case we error about above, but we want to fall back gracefully
-                // so that only the error is being emitted and not also one about the macro
-                // failing.
-                let crate_prefix = format!("{}_", res.krate);
+            // `typeck_foo_bar` => `foo_bar` (in `typeck.ftl`)
+            // `const_eval_baz` => `baz` (in `const_eval.ftl`)
+            // `const-eval-hyphen-having` => `hyphen_having` (in `const_eval.ftl`)
+            // The last case we error about above, but we want to fall back gracefully
+            // so that only the error is being emitted and not also one about the macro
+            // failing.
+            let crate_prefix = format!("{crate_name}_");
 
-                let snake_name = name.replace('-', "_");
-                if !snake_name.starts_with(&crate_prefix) {
+            let snake_name = name.replace('-', "_");
+            if !snake_name.starts_with(&crate_prefix) {
+                Diagnostic::spanned(
+                    resource_span,
+                    Level::Error,
+                    format!("name `{name}` does not start with the crate name"),
+                )
+                .help(format!(
+                    "prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`"
+                ))
+                .emit();
+            };
+            let snake_name = Ident::new(&snake_name, resource_str.span());
+
+            if !previous_attrs.insert(snake_name.clone()) {
+                continue;
+            }
+
+            let msg = format!("Constant referring to Fluent message `{name}` from `{crate_name}`");
+            constants.extend(quote! {
+                #[doc = #msg]
+                pub const #snake_name: crate::DiagnosticMessage =
+                    crate::DiagnosticMessage::FluentIdentifier(
+                        std::borrow::Cow::Borrowed(#name),
+                        None
+                    );
+            });
+
+            for Attribute { id: Identifier { name: attr_name }, .. } in attributes {
+                let snake_name = Ident::new(
+                    &format!("{}{}", &crate_prefix, &attr_name.replace('-', "_")),
+                    resource_str.span(),
+                );
+                if !previous_attrs.insert(snake_name.clone()) {
+                    continue;
+                }
+
+                if attr_name.contains('-') {
                     Diagnostic::spanned(
-                        path_span,
+                        resource_span,
                         Level::Error,
-                        format!("name `{name}` does not start with the crate name"),
+                        format!("attribute `{attr_name}` contains a '-' character"),
                     )
-                    .help(format!(
-                        "prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`"
-                    ))
+                    .help("replace any '-'s with '_'s")
                     .emit();
-                };
-
-                let snake_name = Ident::new(&snake_name, span);
+                }
 
+                let msg = format!(
+                    "Constant referring to Fluent message `{name}.{attr_name}` from `{crate_name}`"
+                );
                 constants.extend(quote! {
-                    pub const #snake_name: crate::DiagnosticMessage =
-                        crate::DiagnosticMessage::FluentIdentifier(
-                            std::borrow::Cow::Borrowed(#name),
-                            None
+                    #[doc = #msg]
+                    pub const #snake_name: crate::SubdiagnosticMessage =
+                        crate::SubdiagnosticMessage::FluentAttr(
+                            std::borrow::Cow::Borrowed(#attr_name)
                         );
                 });
-
-                for Attribute { id: Identifier { name: attr_name }, .. } in attributes {
-                    let snake_name = Ident::new(&attr_name.replace('-', "_"), span);
-                    if !previous_attrs.insert(snake_name.clone()) {
-                        continue;
-                    }
-
-                    if attr_name.contains('-') {
-                        Diagnostic::spanned(
-                            path_span,
-                            Level::Error,
-                            format!("attribute `{attr_name}` contains a '-' character"),
-                        )
-                        .help("replace any '-'s with '_'s")
-                        .emit();
-                    }
-
-                    constants.extend(quote! {
-                        pub const #snake_name: crate::SubdiagnosticMessage =
-                            crate::SubdiagnosticMessage::FluentAttr(
-                                std::borrow::Cow::Borrowed(#attr_name)
-                            );
-                    });
-                }
             }
         }
+    }
 
-        for (mref, name) in messagerefs.into_iter() {
-            if !previous_defns.contains_key(mref) {
-                Diagnostic::spanned(
-                    path_span,
-                    Level::Error,
-                    format!("referenced message `{mref}` does not exist (in message `{name}`)"),
-                )
-                .help(&format!("you may have meant to use a variable reference (`{{${mref}}}`)"))
-                .emit();
-            }
+    for (mref, name) in message_refs.into_iter() {
+        if !previous_defns.contains_key(mref) {
+            Diagnostic::spanned(
+                resource_span,
+                Level::Error,
+                format!("referenced message `{mref}` does not exist (in message `{name}`)"),
+            )
+            .help(&format!("you may have meant to use a variable reference (`{{${mref}}}`)"))
+            .emit();
         }
+    }
 
-        if let Err(errs) = bundle.add_resource(resource) {
-            for e in errs {
-                match e {
-                    FluentError::Overriding { kind, id } => {
-                        Diagnostic::spanned(
-                            path_span,
-                            Level::Error,
-                            format!("overrides existing {kind}: `{id}`"),
-                        )
-                        .span_help(previous_defns[&id], "previously defined in this resource")
-                        .emit();
-                    }
-                    FluentError::ResolverError(_) | FluentError::ParserError(_) => unreachable!(),
+    if let Err(errs) = bundle.add_resource(resource) {
+        for e in errs {
+            match e {
+                FluentError::Overriding { kind, id } => {
+                    Diagnostic::spanned(
+                        resource_span,
+                        Level::Error,
+                        format!("overrides existing {kind}: `{id}`"),
+                    )
+                    .emit();
                 }
+                FluentError::ResolverError(_) | FluentError::ParserError(_) => unreachable!(),
             }
         }
-
-        includes.extend(quote! { include_str!(#relative_ftl_path), });
-
-        generated.extend(constants);
     }
 
     quote! {
+        /// Raw content of Fluent resource for this crate, generated by `fluent_messages` macro,
+        /// imported by `rustc_driver` to include all crates' resources in one bundle.
+        pub static DEFAULT_LOCALE_RESOURCE: &'static str = include_str!(#relative_ftl_path);
+
         #[allow(non_upper_case_globals)]
         #[doc(hidden)]
-        pub mod fluent_generated {
-            pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = &[
-                #includes
-            ];
-
-            #generated
+        /// Auto-generated constants for type-checked references to Fluent messages.
+        pub(crate) mod fluent_generated {
+            #constants
 
+            /// Constants expected to exist by the diagnostic derive macros to use as default Fluent
+            /// identifiers for different subdiagnostic kinds.
             pub mod _subdiag {
+                /// Default for `#[help]`
                 pub const help: crate::SubdiagnosticMessage =
                     crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help"));
+                /// Default for `#[note]`
                 pub const note: crate::SubdiagnosticMessage =
                     crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
+                /// Default for `#[warn]`
                 pub const warn: crate::SubdiagnosticMessage =
                     crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn"));
+                /// Default for `#[label]`
                 pub const label: crate::SubdiagnosticMessage =
                     crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label"));
+                /// Default for `#[suggestion]`
                 pub const suggestion: crate::SubdiagnosticMessage =
                     crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion"));
             }
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 906e4c0b0e16c..90660fc1f93db 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -512,7 +512,9 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
         let mut calls = TokenStream::new();
         for (kind, slug) in kind_slugs {
             let message = format_ident!("__message");
-            calls.extend(quote! { let #message = #f(#diag, rustc_errors::fluent::#slug.into()); });
+            calls.extend(
+                quote! { let #message = #f(#diag, crate::fluent_generated::#slug.into()); },
+            );
 
             let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
             let call = match kind {
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index d2cb6ee9f71fb..737500cc257eb 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -61,9 +61,7 @@ pub fn newtype_index(input: TokenStream) -> TokenStream {
 /// For example, given the following invocation of the macro..
 ///
 /// ```ignore (rust)
-/// fluent_messages! {
-///     typeck => "./typeck.ftl",
-/// }
+/// fluent_messages! { "./typeck.ftl" }
 /// ```
 /// ..where `typeck.ftl` has the following contents..
 ///
@@ -77,9 +75,7 @@ pub fn newtype_index(input: TokenStream) -> TokenStream {
 /// will generate the following code:
 ///
 /// ```ignore (rust)
-/// pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = &[
-///     include_str!("./typeck.ftl"),
-/// ];
+/// pub static DEFAULT_LOCALE_RESOURCE: &'static [&'static str] = include_str!("./typeck.ftl");
 ///
 /// mod fluent_generated {
 ///     mod typeck {
diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_metadata/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/metadata.ftl
rename to compiler/rustc_metadata/locales/en-US.ftl
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index c32686779facb..51b41b5f6a214 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -9,6 +9,7 @@ use rustc_session::config;
 use rustc_span::{sym, Span, Symbol};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 
+use crate::fluent_generated as fluent;
 use crate::locator::CrateFlavor;
 
 #[derive(Diagnostic)]
@@ -491,7 +492,7 @@ impl IntoDiagnostic<'_> for MultipleCandidates {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_multiple_candidates);
+        let mut diag = handler.struct_err(fluent::metadata_multiple_candidates);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("flavor", self.flavor);
         diag.code(error_code!(E0464));
@@ -590,7 +591,7 @@ impl IntoDiagnostic<'_> for InvalidMetadataFiles {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_invalid_meta_files);
+        let mut diag = handler.struct_err(fluent::metadata_invalid_meta_files);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("add_info", self.add_info);
         diag.code(error_code!(E0786));
@@ -619,7 +620,7 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::metadata_cannot_find_crate);
+        let mut diag = handler.struct_err(fluent::metadata_cannot_find_crate);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("current_crate", self.current_crate);
         diag.set_arg("add_info", self.add_info);
@@ -630,32 +631,32 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
             && self.locator_triple != TargetTriple::from_triple(config::host_triple())
         {
             if self.missing_core {
-                diag.note(rustc_errors::fluent::metadata_target_not_installed);
+                diag.note(fluent::metadata_target_not_installed);
             } else {
-                diag.note(rustc_errors::fluent::metadata_target_no_std_support);
+                diag.note(fluent::metadata_target_no_std_support);
             }
             // NOTE: this suggests using rustup, even though the user may not have it installed.
             // That's because they could choose to install it; or this may give them a hint which
             // target they need to install from their distro.
             if self.missing_core {
-                diag.help(rustc_errors::fluent::metadata_consider_downloading_target);
+                diag.help(fluent::metadata_consider_downloading_target);
             }
             // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
             // NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
             // If it's not a dummy, that means someone added `extern crate std` explicitly and
             // `#![no_std]` won't help.
             if !self.missing_core && self.span.is_dummy() {
-                diag.note(rustc_errors::fluent::metadata_std_required);
+                diag.note(fluent::metadata_std_required);
             }
             if self.is_nightly_build {
-                diag.help(rustc_errors::fluent::metadata_consider_building_std);
+                diag.help(fluent::metadata_consider_building_std);
             }
         } else if self.crate_name == self.profiler_runtime {
-            diag.note(rustc_errors::fluent::metadata_compiler_missing_profiler);
+            diag.note(fluent::metadata_compiler_missing_profiler);
         } else if self.crate_name.as_str().starts_with("rustc_") {
-            diag.help(rustc_errors::fluent::metadata_install_missing_components);
+            diag.help(fluent::metadata_install_missing_components);
         }
-        diag.span_label(self.span, rustc_errors::fluent::metadata_cant_find_crate);
+        diag.span_label(self.span, fluent::metadata_cant_find_crate);
         diag
     }
 }
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 1987f88e6b8cc..6f6d3731ceace 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -30,6 +30,8 @@ extern crate rustc_data_structures;
 extern crate tracing;
 
 pub use rmeta::{provide, provide_extern};
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
 
 mod dependency_format;
 mod foreign_modules;
@@ -44,3 +46,5 @@ pub mod locator;
 pub use fs::{emit_wrapper_file, METADATA_FILENAME};
 pub use native_libs::find_native_static_library;
 pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER};
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_middle/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/middle.ftl
rename to compiler/rustc_middle/locales/en-US.ftl
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index e6cd38c0f1584..c33b9d84eb0a0 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -73,6 +73,9 @@ extern crate tracing;
 #[macro_use]
 extern crate smallvec;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 #[cfg(test)]
 mod tests;
 
@@ -105,3 +108,5 @@ pub mod util {
 
 // Allows macros to refer to this crate as `::rustc_middle`
 extern crate self as rustc_middle;
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index a029c1b209df4..bdc5861109243 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -612,3 +612,11 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
         c.try_super_fold_with(self)
     }
 }
+
+#[derive(Diagnostic)]
+#[diag(middle_const_not_used_in_type_alias)]
+pub(super) struct ConstNotUsedTraitAlias {
+    pub ct: String,
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 993191ee96a44..2d92f37704196 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,3 +1,4 @@
+use crate::fluent_generated as fluent;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::normalize_erasing_regions::NormalizationError;
 use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitable};
@@ -182,16 +183,16 @@ impl IntoDiagnostic<'_, !> for LayoutError<'_> {
         match self {
             LayoutError::Unknown(ty) => {
                 diag.set_arg("ty", ty);
-                diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout);
+                diag.set_primary_message(fluent::middle_unknown_layout);
             }
             LayoutError::SizeOverflow(ty) => {
                 diag.set_arg("ty", ty);
-                diag.set_primary_message(rustc_errors::fluent::middle_values_too_big);
+                diag.set_primary_message(fluent::middle_values_too_big);
             }
             LayoutError::NormalizationFailure(ty, e) => {
                 diag.set_arg("ty", ty);
                 diag.set_arg("failure_ty", e.get_type_for_failure());
-                diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized);
+                diag.set_primary_message(fluent::middle_cannot_be_normalized);
             }
         }
         diag
diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_mir_build/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/mir_build.ftl
rename to compiler/rustc_mir_build/locales/en-US.ftl
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index ced251267d36f..c1f6b8b59ce59 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,9 +1,10 @@
-use crate::thir::pattern::deconstruct_pat::DeconstructedPat;
-use crate::thir::pattern::MatchCheckCtxt;
-use rustc_errors::Handler;
+use crate::{
+    fluent_generated as fluent,
+    thir::pattern::{deconstruct_pat::DeconstructedPat, MatchCheckCtxt},
+};
 use rustc_errors::{
     error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-    IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
+    Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
 };
 use rustc_hir::def::Res;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -358,7 +359,7 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::mir_build_non_exhaustive_patterns_type_not_empty,
+            fluent::mir_build_non_exhaustive_patterns_type_not_empty,
             error_code!(E0004),
         );
 
@@ -380,7 +381,7 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
             let mut span: MultiSpan = def_span.into();
             span.push_span_label(def_span, "");
 
-            diag.span_note(span, rustc_errors::fluent::def_note);
+            diag.span_note(span, fluent::mir_build_def_note);
         }
 
         let is_variant_list_non_exhaustive = match self.ty.kind() {
@@ -391,14 +392,14 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
         };
 
         if is_variant_list_non_exhaustive {
-            diag.note(rustc_errors::fluent::non_exhaustive_type_note);
+            diag.note(fluent::mir_build_non_exhaustive_type_note);
         } else {
-            diag.note(rustc_errors::fluent::type_note);
+            diag.note(fluent::mir_build_type_note);
         }
 
         if let ty::Ref(_, sub_ty, _) = self.ty.kind() {
             if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) {
-                diag.note(rustc_errors::fluent::reference_note);
+                diag.note(fluent::mir_build_reference_note);
             }
         }
 
@@ -424,12 +425,12 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
         if let Some((span, sugg)) = suggestion {
             diag.span_suggestion_verbose(
                 span,
-                rustc_errors::fluent::suggestion,
+                fluent::mir_build_suggestion,
                 sugg,
                 Applicability::HasPlaceholders,
             );
         } else {
-            diag.help(rustc_errors::fluent::help);
+            diag.help(fluent::mir_build_help);
         }
 
         diag
@@ -469,7 +470,7 @@ pub struct NonConstPath {
 pub struct UnreachablePattern {
     #[label]
     pub span: Option<Span>,
-    #[label(catchall_label)]
+    #[label(mir_build_catchall_label)]
     pub catchall: Option<Span>,
 }
 
@@ -493,7 +494,7 @@ pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[note(teach_note)]
+    #[note(mir_build_teach_note)]
     pub teach: Option<()>,
 }
 
@@ -585,9 +586,9 @@ pub struct BorrowOfMovedValue<'tcx> {
     #[primary_span]
     pub span: Span,
     #[label]
-    #[label(occurs_because_label)]
+    #[label(mir_build_occurs_because_label)]
     pub binding_span: Span,
-    #[label(value_borrowed_label)]
+    #[label(mir_build_value_borrowed_label)]
     pub conflicts_ref: Vec<Span>,
     pub name: Ident,
     pub ty: Ty<'tcx>,
@@ -708,7 +709,7 @@ pub struct NontrivialStructuralMatch<'tcx> {
 #[diag(mir_build_overlapping_range_endpoints)]
 #[note]
 pub struct OverlappingRangeEndpoints<'tcx> {
-    #[label(range)]
+    #[label(mir_build_range)]
     pub range: Span,
     #[subdiagnostic]
     pub overlap: Vec<Overlap<'tcx>>,
@@ -788,7 +789,7 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
     pub interpreted_as_const: Option<InterpretedAsConst>,
     #[subdiagnostic]
     pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
-    #[note(pattern_ty)]
+    #[note(mir_build_pattern_ty)]
     pub _p: (),
     pub pattern_ty: Ty<'tcx>,
     #[subdiagnostic]
@@ -823,10 +824,10 @@ impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
         let mut spans = MultiSpan::from(self.adt_def_span);
 
         for Variant { span } in self.variants {
-            spans.push_span_label(span, rustc_errors::fluent::mir_build_variant_defined_here);
+            spans.push_span_label(span, fluent::mir_build_variant_defined_here);
         }
 
-        diag.span_note(spans, rustc_errors::fluent::mir_build_adt_defined_here);
+        diag.span_note(spans, fluent::mir_build_adt_defined_here);
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 94dae36154c26..fbc130501f993 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -25,6 +25,11 @@ pub mod thir;
 
 use rustc_middle::ty::query::Providers;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub fn provide(providers: &mut Providers) {
     providers.check_match = thir::pattern::check_match;
     providers.lit_to_const = thir::constant::lit_to_const;
diff --git a/compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl b/compiler/rustc_mir_dataflow/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/mir_dataflow.ftl
rename to compiler/rustc_mir_dataflow/locales/en-US.ftl
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 3e382f500afbe..b1e03faff052d 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -16,7 +16,9 @@ extern crate tracing;
 extern crate rustc_middle;
 
 use rustc_ast::MetaItem;
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir::def_id::DefId;
+use rustc_macros::fluent_messages;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 
@@ -44,6 +46,8 @@ pub mod storage;
 pub mod un_derefer;
 pub mod value_analysis;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub(crate) mod indexes {
     pub(crate) use super::move_paths::MovePathIndex;
 }
diff --git a/compiler/rustc_error_messages/locales/en-US/monomorphize.ftl b/compiler/rustc_monomorphize/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/monomorphize.ftl
rename to compiler/rustc_monomorphize/locales/en-US.ftl
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index a53bd7e1fef5e..495a73490a217 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -1,5 +1,6 @@
 use std::path::PathBuf;
 
+use crate::fluent_generated as fluent;
 use rustc_errors::ErrorGuaranteed;
 use rustc_errors::IntoDiagnostic;
 use rustc_macros::{Diagnostic, LintDiagnostic};
@@ -44,7 +45,7 @@ impl IntoDiagnostic<'_> for UnusedGenericParamsHint {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::monomorphize_unused_generic_params);
+        let mut diag = handler.struct_err(fluent::monomorphize_unused_generic_params);
         diag.set_span(self.span);
         for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
             // FIXME: I can figure out how to do a label with a fluent string with a fixed message,
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index f88155e4fc792..f6b791f29c178 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -9,7 +9,9 @@ extern crate tracing;
 #[macro_use]
 extern crate rustc_middle;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir::lang_items::LangItem;
+use rustc_macros::fluent_messages;
 use rustc_middle::traits;
 use rustc_middle::ty::adjustment::CustomCoerceUnsized;
 use rustc_middle::ty::query::{Providers, TyCtxtAt};
@@ -21,6 +23,8 @@ mod partitioning;
 mod polymorphize;
 mod util;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 fn custom_coerce_unsize_info<'tcx>(
     tcx: TyCtxtAt<'tcx>,
     source_ty: Ty<'tcx>,
diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_parse/locales/en-US.ftl
similarity index 96%
rename from compiler/rustc_error_messages/locales/en-US/parse.ftl
rename to compiler/rustc_parse/locales/en-US.ftl
index c9cf7b62071fe..a31b1f6ac1a0a 100644
--- a/compiler/rustc_error_messages/locales/en-US/parse.ftl
+++ b/compiler/rustc_parse/locales/en-US.ftl
@@ -93,6 +93,26 @@ parse_do_catch_syntax_removed = found removed `do catch` syntax
 parse_float_literal_requires_integer_part = float literals must have an integer part
     .suggestion = must have an integer part
 
+parse_invalid_int_literal_width = invalid width `{$width}` for integer literal
+    .help = valid widths are 8, 16, 32, 64 and 128
+
+parse_invalid_num_literal_base_prefix = invalid base prefix for number literal
+    .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
+    .suggestion = try making the prefix lowercase
+
+parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
+    .label = invalid suffix `{$suffix}`
+    .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+parse_invalid_float_literal_width = invalid width `{$width}` for float literal
+    .help = valid widths are 32 and 64
+
+parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
+    .label = invalid suffix `{$suffix}`
+    .help = valid suffixes are `f32` and `f64`
+
+parse_int_literal_too_large = integer literal is too large
+
 parse_missing_semicolon_before_array = expected `;`, found `[`
     .suggestion = consider adding `;` here
 
@@ -219,6 +239,14 @@ parse_struct_literal_not_allowed_here = struct literals are not allowed here
 
 parse_invalid_interpolated_expression = invalid interpolated expression
 
+parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+parse_octal_float_literal_not_supported = octal float literal is not supported
+parse_binary_float_literal_not_supported = binary float literal is not supported
+parse_not_supported = not supported
+
+parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid
+    .label = invalid suffix `{$suffix}`
+
 parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
     .label = invalid suffix `{$suffix}`
     .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 63bf864f2a812..c746a87096476 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2,13 +2,14 @@ use std::borrow::Cow;
 
 use rustc_ast::token::Token;
 use rustc_ast::{Path, Visibility};
-use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic};
+use rustc_errors::{AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, Symbol};
 
+use crate::fluent_generated as fluent;
 use crate::parser::TokenDescription;
 
 #[derive(Diagnostic)]
@@ -78,7 +79,7 @@ pub(crate) struct IncorrectSemicolon<'a> {
 #[diag(parse_incorrect_use_of_await)]
 pub(crate) struct IncorrectUseOfAwait {
     #[primary_span]
-    #[suggestion(parentheses_suggestion, code = "", applicability = "machine-applicable")]
+    #[suggestion(parse_parentheses_suggestion, code = "", applicability = "machine-applicable")]
     pub span: Span,
 }
 
@@ -87,7 +88,7 @@ pub(crate) struct IncorrectUseOfAwait {
 pub(crate) struct IncorrectAwait {
     #[primary_span]
     pub span: Span,
-    #[suggestion(postfix_suggestion, code = "{expr}.await{question_mark}")]
+    #[suggestion(parse_postfix_suggestion, code = "{expr}.await{question_mark}")]
     pub sugg_span: (Span, Applicability),
     pub expr: String,
     pub question_mark: &'static str,
@@ -140,7 +141,7 @@ pub(crate) struct InvalidComparisonOperator {
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidComparisonOperatorSub {
     #[suggestion(
-        use_instead,
+        parse_use_instead,
         style = "short",
         applicability = "machine-applicable",
         code = "{correct}"
@@ -151,7 +152,7 @@ pub(crate) enum InvalidComparisonOperatorSub {
         invalid: String,
         correct: String,
     },
-    #[label(spaceship_operator_invalid)]
+    #[label(parse_spaceship_operator_invalid)]
     Spaceship(#[primary_span] Span),
 }
 
@@ -169,14 +170,14 @@ pub(crate) struct InvalidLogicalOperator {
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidLogicalOperatorSub {
     #[suggestion(
-        use_amp_amp_for_conjunction,
+        parse_use_amp_amp_for_conjunction,
         style = "short",
         applicability = "machine-applicable",
         code = "&&"
     )]
     Conjunction(#[primary_span] Span),
     #[suggestion(
-        use_pipe_pipe_for_disjunction,
+        parse_use_pipe_pipe_for_disjunction,
         style = "short",
         applicability = "machine-applicable",
         code = "||"
@@ -262,14 +263,14 @@ pub(crate) struct UnexpectedTokenAfterLabel {
     #[primary_span]
     #[label(parse_unexpected_token_after_label)]
     pub span: Span,
-    #[suggestion(suggestion_remove_label, style = "verbose", code = "")]
+    #[suggestion(parse_suggestion_remove_label, style = "verbose", code = "")]
     pub remove_label: Option<Span>,
     #[subdiagnostic]
     pub enclose_in_block: Option<UnexpectedTokenAfterLabelSugg>,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion_enclose_in_block, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion_enclose_in_block, applicability = "machine-applicable")]
 pub(crate) struct UnexpectedTokenAfterLabelSugg {
     #[suggestion_part(code = "{{ ")]
     pub left: Span,
@@ -347,9 +348,9 @@ pub(crate) struct IfExpressionMissingThenBlock {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum IfExpressionMissingThenBlockSub {
-    #[help(condition_possibly_unfinished)]
+    #[help(parse_condition_possibly_unfinished)]
     UnfinishedCondition(#[primary_span] Span),
-    #[help(add_then_block)]
+    #[help(parse_add_then_block)]
     AddThenBlock(#[primary_span] Span),
 }
 
@@ -364,9 +365,9 @@ pub(crate) struct IfExpressionLetSomeSub {
 #[diag(parse_if_expression_missing_condition)]
 pub(crate) struct IfExpressionMissingCondition {
     #[primary_span]
-    #[label(condition_label)]
+    #[label(parse_condition_label)]
     pub if_span: Span,
-    #[label(block_label)]
+    #[label(parse_block_label)]
     pub block_span: Span,
 }
 
@@ -404,10 +405,10 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse {
     #[primary_span]
     pub last: Span,
 
-    #[label(branch_label)]
+    #[label(parse_branch_label)]
     pub branch_span: Span,
 
-    #[label(ctx_label)]
+    #[label(parse_ctx_label)]
     pub ctx_span: Span,
     pub ctx: String,
 
@@ -427,9 +428,14 @@ pub(crate) struct MissingInInForLoop {
 #[derive(Subdiagnostic)]
 pub(crate) enum MissingInInForLoopSub {
     // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
-    #[suggestion(use_in_not_of, style = "short", applicability = "maybe-incorrect", code = "in")]
+    #[suggestion(
+        parse_use_in_not_of,
+        style = "short",
+        applicability = "maybe-incorrect",
+        code = "in"
+    )]
     InNotOf(#[primary_span] Span),
-    #[suggestion(add_in, style = "short", applicability = "maybe-incorrect", code = " in ")]
+    #[suggestion(parse_add_in, style = "short", applicability = "maybe-incorrect", code = " in ")]
     AddIn(#[primary_span] Span),
 }
 
@@ -484,8 +490,8 @@ pub(crate) struct EqFieldInit {
 #[diag(parse_dotdotdot)]
 pub(crate) struct DotDotDot {
     #[primary_span]
-    #[suggestion(suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
-    #[suggestion(suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+    #[suggestion(parse_suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
+    #[suggestion(parse_suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
     pub span: Span,
 }
 
@@ -525,10 +531,10 @@ pub(crate) struct UseEmptyBlockNotSemi {
 #[diag(parse_comparison_interpreted_as_generic)]
 pub(crate) struct ComparisonInterpretedAsGeneric {
     #[primary_span]
-    #[label(label_comparison)]
+    #[label(parse_label_comparison)]
     pub comparison: Span,
     pub r#type: Path,
-    #[label(label_args)]
+    #[label(parse_label_args)]
     pub args: Span,
     #[subdiagnostic]
     pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
@@ -538,17 +544,17 @@ pub(crate) struct ComparisonInterpretedAsGeneric {
 #[diag(parse_shift_interpreted_as_generic)]
 pub(crate) struct ShiftInterpretedAsGeneric {
     #[primary_span]
-    #[label(label_comparison)]
+    #[label(parse_label_comparison)]
     pub shift: Span,
     pub r#type: Path,
-    #[label(label_args)]
+    #[label(parse_label_args)]
     pub args: Span,
     #[subdiagnostic]
     pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg {
     #[suggestion_part(code = "(")]
     pub left: Span,
@@ -574,7 +580,7 @@ pub(crate) struct LeadingPlusNotSupported {
     #[label]
     pub span: Span,
     #[suggestion(
-        suggestion_remove_plus,
+        parse_suggestion_remove_plus,
         style = "verbose",
         code = "",
         applicability = "machine-applicable"
@@ -597,7 +603,7 @@ pub(crate) struct ParenthesesWithStructFields {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion_braces_for_struct, applicability = "maybe-incorrect")]
+#[multipart_suggestion(parse_suggestion_braces_for_struct, applicability = "maybe-incorrect")]
 pub(crate) struct BracesForStructLiteral {
     #[suggestion_part(code = " {{ ")]
     pub first: Span,
@@ -606,7 +612,7 @@ pub(crate) struct BracesForStructLiteral {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion_no_fields_for_fn, applicability = "maybe-incorrect")]
+#[multipart_suggestion(parse_suggestion_no_fields_for_fn, applicability = "maybe-incorrect")]
 pub(crate) struct NoFieldsForFnCall {
     #[suggestion_part(code = "")]
     pub fields: Vec<Span>,
@@ -643,7 +649,7 @@ pub(crate) struct ArrayBracketsInsteadOfSpaces {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
+#[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")]
 pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
     #[suggestion_part(code = "[")]
     pub left: Span,
@@ -655,9 +661,9 @@ pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
 #[diag(parse_match_arm_body_without_braces)]
 pub(crate) struct MatchArmBodyWithoutBraces {
     #[primary_span]
-    #[label(label_statements)]
+    #[label(parse_label_statements)]
     pub statements: Span,
-    #[label(label_arrow)]
+    #[label(parse_label_arrow)]
     pub arrow: Span,
     pub num_statements: usize,
     #[subdiagnostic]
@@ -670,7 +676,7 @@ pub(crate) struct MatchArmBodyWithoutBraces {
 pub(crate) struct InclusiveRangeExtraEquals {
     #[primary_span]
     #[suggestion(
-        suggestion_remove_eq,
+        parse_suggestion_remove_eq,
         style = "short",
         code = "..=",
         applicability = "maybe-incorrect"
@@ -695,7 +701,7 @@ pub(crate) struct InclusiveRangeMatchArrow {
 pub(crate) struct InclusiveRangeNoEnd {
     #[primary_span]
     #[suggestion(
-        suggestion_open_range,
+        parse_suggestion_open_range,
         code = "..",
         applicability = "machine-applicable",
         style = "short"
@@ -705,7 +711,7 @@ pub(crate) struct InclusiveRangeNoEnd {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum MatchArmBodyWithoutBracesSugg {
-    #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
+    #[multipart_suggestion(parse_suggestion_add_braces, applicability = "machine-applicable")]
     AddBraces {
         #[suggestion_part(code = "{{ ")]
         left: Span,
@@ -713,7 +719,7 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg {
         right: Span,
     },
     #[suggestion(
-        suggestion_use_comma_not_semicolon,
+        parse_suggestion_use_comma_not_semicolon,
         code = ",",
         applicability = "machine-applicable"
     )]
@@ -733,7 +739,7 @@ pub(crate) struct StructLiteralNotAllowedHere {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct StructLiteralNotAllowedHereSugg {
     #[suggestion_part(code = "(")]
     pub left: Span,
@@ -755,9 +761,9 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
     #[label]
     pub span: Span,
     pub suffix: Symbol,
-    #[help(tuple_exception_line_1)]
-    #[help(tuple_exception_line_2)]
-    #[help(tuple_exception_line_3)]
+    #[help(parse_tuple_exception_line_1)]
+    #[help(parse_tuple_exception_line_2)]
+    #[help(parse_tuple_exception_line_3)]
     pub exception: Option<()>,
 }
 
@@ -775,11 +781,11 @@ pub(crate) struct MismatchedClosingDelimiter {
     #[primary_span]
     pub spans: Vec<Span>,
     pub delimiter: String,
-    #[label(label_unmatched)]
+    #[label(parse_label_unmatched)]
     pub unmatched: Span,
-    #[label(label_opening_candidate)]
+    #[label(parse_label_opening_candidate)]
     pub opening_candidate: Option<Span>,
-    #[label(label_unclosed)]
+    #[label(parse_label_unclosed)]
     pub unclosed: Option<Span>,
 }
 
@@ -930,7 +936,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
         self,
         handler: &'a rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'a, G> {
-        let token_descr = super::parser::TokenDescription::from_token(&self.token);
+        let token_descr = TokenDescription::from_token(&self.token);
 
         let mut diag = handler.struct_diagnostic(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
@@ -976,7 +982,7 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
         self,
         handler: &'a rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'a, G> {
-        let token_descr = super::parser::TokenDescription::from_token(&self.token);
+        let token_descr = TokenDescription::from_token(&self.token);
 
         let mut diag = handler.struct_diagnostic(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
@@ -1025,7 +1031,7 @@ pub(crate) struct StructLiteralBodyWithoutPath {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "has-placeholders")]
+#[multipart_suggestion(parse_suggestion, applicability = "has-placeholders")]
 pub(crate) struct StructLiteralBodyWithoutPathSugg {
     #[suggestion_part(code = "{{ SomeStruct ")]
     pub before: Span,
@@ -1043,7 +1049,7 @@ pub(crate) struct StructLiteralNeedingParens {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct StructLiteralNeedingParensSugg {
     #[suggestion_part(code = "(")]
     pub before: Span,
@@ -1070,7 +1076,7 @@ pub(crate) struct GenericParamsWithoutAngleBrackets {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct GenericParamsWithoutAngleBracketsSugg {
     #[suggestion_part(code = "<")]
     pub left: Span,
@@ -1091,7 +1097,7 @@ pub(crate) struct ComparisonOperatorsCannotBeChained {
     )]
     pub suggest_turbofish: Option<Span>,
     #[help(parse_sugg_turbofish_syntax)]
-    #[help(sugg_parentheses_for_function_args)]
+    #[help(parse_sugg_parentheses_for_function_args)]
     pub help_turbofish: Option<()>,
     #[subdiagnostic]
     pub chaining_sugg: Option<ComparisonOperatorsCannotBeChainedSugg>,
@@ -1100,7 +1106,7 @@ pub(crate) struct ComparisonOperatorsCannotBeChained {
 #[derive(Subdiagnostic)]
 pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
     #[suggestion(
-        sugg_split_comparison,
+        parse_sugg_split_comparison,
         style = "verbose",
         code = " && {middle_term}",
         applicability = "maybe-incorrect"
@@ -1110,7 +1116,7 @@ pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
         span: Span,
         middle_term: String,
     },
-    #[multipart_suggestion(sugg_parenthesize, applicability = "maybe-incorrect")]
+    #[multipart_suggestion(parse_sugg_parenthesize, applicability = "maybe-incorrect")]
     Parenthesize {
         #[suggestion_part(code = "(")]
         left: Span,
@@ -1130,7 +1136,7 @@ pub(crate) struct QuestionMarkInType {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct QuestionMarkInTypeSugg {
     #[suggestion_part(code = "Option<")]
     pub left: Span,
@@ -1148,7 +1154,7 @@ pub(crate) struct ParenthesesInForHead {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct ParenthesesInForHeadSugg {
     #[suggestion_part(code = "{left_snippet}")]
     pub left: Span,
@@ -1208,7 +1214,7 @@ pub(crate) struct ConstGenericWithoutBraces {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct ConstGenericWithoutBracesSugg {
     #[suggestion_part(code = "{{ ")]
     pub left: Span,
@@ -1228,7 +1234,7 @@ pub(crate) struct UnexpectedConstParamDeclaration {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum UnexpectedConstParamDeclarationSugg {
-    #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+    #[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
     AddParam {
         #[suggestion_part(code = "<{snippet}>")]
         impl_generics: Span,
@@ -1237,7 +1243,7 @@ pub(crate) enum UnexpectedConstParamDeclarationSugg {
         snippet: String,
         ident: String,
     },
-    #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+    #[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
     AppendParam {
         #[suggestion_part(code = ", {snippet}")]
         impl_generics_end: Span,
@@ -1284,7 +1290,7 @@ pub(crate) struct FnPtrWithGenerics {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
+#[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")]
 pub(crate) struct FnPtrWithGenericsSugg {
     #[suggestion_part(code = "{snippet}")]
     pub left: Span,
@@ -1325,16 +1331,16 @@ pub(crate) struct WhereClauseBeforeTupleStructBody {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(name_label)]
+    #[label(parse_name_label)]
     pub name: Span,
-    #[label(body_label)]
+    #[label(parse_body_label)]
     pub body: Span,
     #[subdiagnostic]
     pub sugg: Option<WhereClauseBeforeTupleStructBodySugg>,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct WhereClauseBeforeTupleStructBodySugg {
     #[suggestion_part(code = "{snippet}")]
     pub left: Span,
@@ -1429,13 +1435,13 @@ pub(crate) enum MissingKeywordForItemDefinition {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum AmbiguousMissingKwForItemSub {
-    #[suggestion(suggestion, applicability = "maybe-incorrect", code = "{snippet}!")]
+    #[suggestion(parse_suggestion, applicability = "maybe-incorrect", code = "{snippet}!")]
     SuggestMacro {
         #[primary_span]
         span: Span,
         snippet: String,
     },
-    #[help(help)]
+    #[help(parse_help)]
     HelpMacro,
 }
 
@@ -1443,9 +1449,9 @@ pub(crate) enum AmbiguousMissingKwForItemSub {
 #[diag(parse_missing_trait_in_trait_impl)]
 pub(crate) struct MissingTraitInTraitImpl {
     #[primary_span]
-    #[suggestion(suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")]
+    #[suggestion(parse_suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")]
     pub span: Span,
-    #[suggestion(suggestion_remove_for, code = "", applicability = "maybe-incorrect")]
+    #[suggestion(parse_suggestion_remove_for, code = "", applicability = "maybe-incorrect")]
     pub for_span: Span,
 }
 
@@ -1505,7 +1511,7 @@ pub(crate) struct ExternCrateNameWithDashes {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct ExternCrateNameWithDashesSugg {
     #[suggestion_part(code = "_")]
     pub dashes: Vec<Span>,
@@ -1726,10 +1732,15 @@ pub struct UnknownPrefix<'a> {
 
 #[derive(Subdiagnostic)]
 pub enum UnknownPrefixSugg {
-    #[suggestion(suggestion_br, code = "br", applicability = "maybe-incorrect", style = "verbose")]
+    #[suggestion(
+        parse_suggestion_br,
+        code = "br",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     UseBr(#[primary_span] Span),
     #[suggestion(
-        suggestion_whitespace,
+        parse_suggestion_whitespace,
         code = " ",
         applicability = "maybe-incorrect",
         style = "verbose"
@@ -1761,7 +1772,7 @@ pub struct UnknownTokenStart {
 
 #[derive(Subdiagnostic)]
 pub enum TokenSubstitution {
-    #[suggestion(sugg_quotes, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(parse_sugg_quotes, code = "{suggestion}", applicability = "maybe-incorrect")]
     DirectedQuotes {
         #[primary_span]
         span: Span,
@@ -1769,7 +1780,7 @@ pub enum TokenSubstitution {
         ascii_str: &'static str,
         ascii_name: &'static str,
     },
-    #[suggestion(sugg_other, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(parse_sugg_other, code = "{suggestion}", applicability = "maybe-incorrect")]
     Other {
         #[primary_span]
         span: Span,
@@ -1782,13 +1793,13 @@ pub enum TokenSubstitution {
 }
 
 #[derive(Subdiagnostic)]
-#[note(note_repeats)]
+#[note(parse_note_repeats)]
 pub struct UnknownTokenRepeat {
     pub repeats: usize,
 }
 
 #[derive(Subdiagnostic)]
-#[help(help_null)]
+#[help(parse_help_null)]
 pub struct UnknownTokenNull;
 
 #[derive(Diagnostic)]
@@ -1805,7 +1816,7 @@ pub enum UnescapeError {
     EscapeOnlyChar {
         #[primary_span]
         span: Span,
-        #[suggestion(escape, applicability = "machine-applicable", code = "{escaped_sugg}")]
+        #[suggestion(parse_escape, applicability = "machine-applicable", code = "{escaped_sugg}")]
         char_span: Span,
         escaped_sugg: String,
         escaped_msg: String,
@@ -1814,7 +1825,7 @@ pub enum UnescapeError {
     #[diag(parse_bare_cr)]
     BareCr {
         #[primary_span]
-        #[suggestion(escape, applicability = "machine-applicable", code = "\\r")]
+        #[suggestion(parse_escape, applicability = "machine-applicable", code = "\\r")]
         span: Span,
         double_quotes: bool,
     },
@@ -1854,7 +1865,12 @@ pub enum UnescapeError {
         #[primary_span]
         #[label]
         Span,
-        #[suggestion(terminate, code = "}}", applicability = "maybe-incorrect", style = "verbose")]
+        #[suggestion(
+            parse_terminate,
+            code = "}}",
+            applicability = "maybe-incorrect",
+            style = "verbose"
+        )]
         Span,
     ),
     #[diag(parse_no_brace_unicode_escape)]
@@ -1918,20 +1934,24 @@ pub enum UnescapeError {
 
 #[derive(Subdiagnostic)]
 pub enum MoreThanOneCharSugg {
-    #[suggestion(consider_normalized, code = "{normalized}", applicability = "machine-applicable")]
+    #[suggestion(
+        parse_consider_normalized,
+        code = "{normalized}",
+        applicability = "machine-applicable"
+    )]
     NormalizedForm {
         #[primary_span]
         span: Span,
         ch: String,
         normalized: String,
     },
-    #[suggestion(remove_non, code = "{ch}", applicability = "maybe-incorrect")]
+    #[suggestion(parse_remove_non, code = "{ch}", applicability = "maybe-incorrect")]
     RemoveNonPrinting {
         #[primary_span]
         span: Span,
         ch: String,
     },
-    #[suggestion(use_double_quotes, code = "{sugg}", applicability = "machine-applicable")]
+    #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")]
     Quotes {
         #[primary_span]
         span: Span,
@@ -1942,7 +1962,7 @@ pub enum MoreThanOneCharSugg {
 
 #[derive(Subdiagnostic)]
 pub enum MoreThanOneCharNote {
-    #[note(followed_by)]
+    #[note(parse_followed_by)]
     AllCombining {
         #[primary_span]
         span: Span,
@@ -1950,7 +1970,7 @@ pub enum MoreThanOneCharNote {
         len: usize,
         escaped_marks: String,
     },
-    #[note(non_printing)]
+    #[note(parse_non_printing)]
     NonPrinting {
         #[primary_span]
         span: Span,
@@ -1960,13 +1980,13 @@ pub enum MoreThanOneCharNote {
 
 #[derive(Subdiagnostic)]
 pub enum NoBraceUnicodeSub {
-    #[suggestion(use_braces, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(parse_use_braces, code = "{suggestion}", applicability = "maybe-incorrect")]
     Suggestion {
         #[primary_span]
         span: Span,
         suggestion: String,
     },
-    #[help(format_of_unicode)]
+    #[help(parse_format_of_unicode)]
     Help,
 }
 
@@ -2042,9 +2062,9 @@ pub(crate) struct PatternOnWrongSideOfAt {
     #[suggestion(code = "{whole_pat}", applicability = "machine-applicable")]
     pub whole_span: Span,
     pub whole_pat: String,
-    #[label(label_pattern)]
+    #[label(parse_label_pattern)]
     pub pattern: Span,
-    #[label(label_binding)]
+    #[label(parse_label_binding)]
     pub binding: Span,
 }
 
@@ -2054,9 +2074,9 @@ pub(crate) struct PatternOnWrongSideOfAt {
 pub(crate) struct ExpectedBindingLeftOfAt {
     #[primary_span]
     pub whole_span: Span,
-    #[label(label_lhs)]
+    #[label(parse_label_lhs)]
     pub lhs: Span,
-    #[label(label_rhs)]
+    #[label(parse_label_rhs)]
     pub rhs: Span,
 }
 
@@ -2236,7 +2256,7 @@ pub(crate) struct NegativeBoundsNotSupported {
 
 #[derive(Subdiagnostic)]
 #[suggestion(
-    suggestion,
+    parse_suggestion,
     style = "tool-only",
     code = "{fixed}",
     applicability = "machine-applicable"
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index b49a01d75ed54..6f37e9758fcbb 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -19,6 +19,8 @@ use rustc_ast::{AttrItem, Attribute, MetaItem};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult};
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
 use rustc_session::parse::ParseSess;
 use rustc_span::{FileName, SourceFile, Span};
 
@@ -34,6 +36,8 @@ pub mod validate_attr;
 
 mod errors;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 // A bunch of utility functions of the form `parse_<thing>_from_<source>`
 // where <thing> includes crate, expr, item, stmt, tts, and one that
 // uses a HOF to parse anything, and <source> includes file and
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 9fa657e725cf2..e3e7c63e3448c 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,10 +1,11 @@
 use crate::errors::{InvalidMetaItem, SuffixedLiteralInAttribute};
+use crate::fluent_generated as fluent;
 
 use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Delimiter, Nonterminal};
-use rustc_errors::{error_code, fluent, Diagnostic, IntoDiagnostic, PResult};
+use rustc_errors::{error_code, Diagnostic, IntoDiagnostic, PResult};
 use rustc_span::{sym, BytePos, Span};
 use std::convert::TryInto;
 use thin_vec::ThinVec;
@@ -68,10 +69,10 @@ impl<'a> Parser<'a> {
                             token::CommentKind::Block => OuterAttributeType::DocBlockComment,
                         },
                     ) {
-                        err.note(fluent::note);
+                        err.note(fluent::parse_note);
                         err.span_suggestion_verbose(
                             replacement_span,
-                            fluent::suggestion,
+                            fluent::parse_suggestion,
                             "",
                             rustc_errors::Applicability::MachineApplicable,
                         );
@@ -175,10 +176,10 @@ impl<'a> Parser<'a> {
             Ok(Some(item)) => {
                 // FIXME(#100717)
                 err.set_arg("item", item.kind.descr());
-                err.span_label(item.span, fluent::label_does_not_annotate_this);
+                err.span_label(item.span, fluent::parse_label_does_not_annotate_this);
                 err.span_suggestion_verbose(
                     replacement_span,
-                    fluent::sugg_change_inner_to_outer,
+                    fluent::parse_sugg_change_inner_to_outer,
                     match attr_type {
                         OuterAttributeType::Attribute => "",
                         OuterAttributeType::DocBlockComment => "*",
@@ -204,8 +205,8 @@ impl<'a> Parser<'a> {
                         attr_sp,
                         fluent::parse_inner_attr_not_permitted_after_outer_doc_comment,
                     );
-                    diag.span_label(attr_sp, fluent::label_attr)
-                        .span_label(prev_doc_comment_span, fluent::label_prev_doc_comment);
+                    diag.span_label(attr_sp, fluent::parse_label_attr)
+                        .span_label(prev_doc_comment_span, fluent::parse_label_prev_doc_comment);
                     diag
                 }
                 Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => {
@@ -213,8 +214,8 @@ impl<'a> Parser<'a> {
                         attr_sp,
                         fluent::parse_inner_attr_not_permitted_after_outer_attr,
                     );
-                    diag.span_label(attr_sp, fluent::label_attr)
-                        .span_label(prev_outer_attr_sp, fluent::label_prev_attr);
+                    diag.span_label(attr_sp, fluent::parse_label_attr)
+                        .span_label(prev_outer_attr_sp, fluent::parse_label_prev_attr);
                     diag
                 }
                 Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 46685dcc45dd8..d235b8a8176a8 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -18,6 +18,7 @@ use crate::errors::{
     UseEqInstead,
 };
 
+use crate::fluent_generated as fluent;
 use crate::lexer::UnmatchedBrace;
 use crate::parser;
 use rustc_ast as ast;
@@ -32,10 +33,9 @@ use rustc_ast::{
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
-    fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, FatalError, Handler, MultiSpan,
-    PResult,
+    pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
+    FatalError, Handler, IntoDiagnostic, MultiSpan, PResult,
 };
-use rustc_errors::{pluralize, Diagnostic, ErrorGuaranteed, IntoDiagnostic};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident};
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 94f7031fad231..8e920f1c42143 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -8,6 +8,7 @@ use crate::errors::{
     TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam,
     UnexpectedVertVertInPattern,
 };
+use crate::fluent_generated as fluent;
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
@@ -17,9 +18,7 @@ use rustc_ast::{
     PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
 };
 use rustc_ast_pretty::pprust;
-use rustc_errors::{
-    fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
-};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::{respan, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_passes/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/passes.ftl
rename to compiler/rustc_passes/locales/en-US.ftl
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 8ad4a5ef95813..bb09dcbdd6980 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,10 +4,10 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use crate::errors;
+use crate::{errors, fluent_generated as fluent};
 use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{fluent, Applicability, IntoDiagnosticArg, MultiSpan};
+use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan};
 use rustc_expand::base::resolve_path;
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
@@ -935,15 +935,15 @@ impl CheckAttrVisitor<'_> {
                             src.insert(1, '!');
                             err.span_suggestion_verbose(
                                 attr.span,
-                                fluent::suggestion,
+                                fluent::passes_suggestion,
                                 src,
                                 Applicability::MaybeIncorrect,
                             );
                         } else {
-                            err.span_help(attr.span, fluent::help);
+                            err.span_help(attr.span, fluent::passes_help);
                         }
                     }
-                    err.note(fluent::note);
+                    err.note(fluent::passes_note);
                     err
                 },
             );
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 68b098e3457b7..82fc3eeff94ab 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -3,6 +3,7 @@ use std::{
     path::{Path, PathBuf},
 };
 
+use crate::fluent_generated as fluent;
 use rustc_ast::Label;
 use rustc_errors::{
     error_code, Applicability, DiagnosticSymbolList, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
@@ -261,7 +262,7 @@ pub struct DocKeywordConflict {
 pub struct DocInlineOnlyUse {
     #[label]
     pub attr_span: Span,
-    #[label(not_a_use_item_label)]
+    #[label(passes_not_a_use_item_label)]
     pub item_span: Option<Span>,
 }
 
@@ -300,7 +301,7 @@ pub struct DocTestUnknownAny {
 #[derive(LintDiagnostic)]
 #[diag(passes_doc_test_unknown_spotlight)]
 #[note]
-#[note(no_op_note)]
+#[note(passes_no_op_note)]
 pub struct DocTestUnknownSpotlight {
     pub path: String,
     #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")]
@@ -573,9 +574,9 @@ pub struct DebugVisualizerPlacement {
 
 #[derive(Diagnostic)]
 #[diag(passes_debug_visualizer_invalid)]
-#[note(note_1)]
-#[note(note_2)]
-#[note(note_3)]
+#[note(passes_note_1)]
+#[note(passes_note_2)]
+#[note(passes_note_3)]
 pub struct DebugVisualizerInvalid {
     #[primary_span]
     pub span: Span,
@@ -782,7 +783,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
         self,
         handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(rustc_errors::fluent::passes_invalid_attr_at_crate_level);
+        let mut diag = handler.struct_err(fluent::passes_invalid_attr_at_crate_level);
         diag.set_span(self.span);
         diag.set_arg("name", self.name);
         // Only emit an error with a suggestion if we can create a string out
@@ -791,7 +792,7 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
             let replacement = src.replace("#!", "#");
             diag.span_suggestion_verbose(
                 self.span,
-                rustc_errors::fluent::suggestion,
+                fluent::passes_suggestion,
                 replacement,
                 rustc_errors::Applicability::MachineApplicable,
             );
@@ -917,17 +918,17 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::passes_break_non_loop,
+            fluent::passes_break_non_loop,
             error_code!(E0571),
         );
         diag.set_arg("kind", self.kind);
-        diag.span_label(self.span, rustc_errors::fluent::label);
+        diag.span_label(self.span, fluent::passes_label);
         if let Some(head) = self.head {
-            diag.span_label(head, rustc_errors::fluent::label2);
+            diag.span_label(head, fluent::passes_label2);
         }
         diag.span_suggestion(
             self.span,
-            rustc_errors::fluent::suggestion,
+            fluent::passes_suggestion,
             self.suggestion,
             Applicability::MaybeIncorrect,
         );
@@ -945,7 +946,7 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
                 _ => {
                     diag.span_suggestion(
                         self.break_expr_span,
-                        rustc_errors::fluent::break_expr_suggestion,
+                        fluent::passes_break_expr_suggestion,
                         label.ident,
                         Applicability::MaybeIncorrect,
                     );
@@ -962,7 +963,7 @@ pub struct ContinueLabeledBlock {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(block_label)]
+    #[label(passes_block_label)]
     pub block_span: Span,
 }
 
@@ -972,7 +973,7 @@ pub struct BreakInsideClosure<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(closure_label)]
+    #[label(passes_closure_label)]
     pub closure_span: Span,
     pub name: &'a str,
 }
@@ -983,7 +984,7 @@ pub struct BreakInsideAsyncBlock<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(async_block_label)]
+    #[label(passes_async_block_label)]
     pub closure_span: Span,
     pub name: &'a str,
 }
@@ -1056,14 +1057,14 @@ impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::passes_naked_functions_asm_block,
+            fluent::passes_naked_functions_asm_block,
             error_code!(E0787),
         );
         for span in self.multiple_asms.iter() {
-            diag.span_label(*span, rustc_errors::fluent::label_multiple_asm);
+            diag.span_label(*span, fluent::passes_label_multiple_asm);
         }
         for span in self.non_asms.iter() {
-            diag.span_label(*span, rustc_errors::fluent::label_non_asm);
+            diag.span_label(*span, fluent::passes_label_non_asm);
         }
         diag
     }
@@ -1122,9 +1123,9 @@ pub struct AttrOnlyInFunctions {
 pub struct MultipleRustcMain {
     #[primary_span]
     pub span: Span,
-    #[label(first)]
+    #[label(passes_first)]
     pub first: Span,
-    #[label(additional)]
+    #[label(passes_additional)]
     pub additional: Span,
 }
 
@@ -1135,7 +1136,7 @@ pub struct MultipleStartFunctions {
     pub span: Span,
     #[label]
     pub labeled: Span,
-    #[label(previous)]
+    #[label(passes_previous)]
     pub previous: Span,
 }
 
@@ -1180,7 +1181,7 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut diag = handler.struct_span_err_with_code(
             DUMMY_SP,
-            rustc_errors::fluent::passes_no_main_function,
+            fluent::passes_no_main_function,
             error_code!(E0601),
         );
         diag.set_arg("crate_name", self.crate_name);
@@ -1188,16 +1189,16 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
         diag.set_arg("has_filename", self.has_filename);
         let note = if !self.non_main_fns.is_empty() {
             for &span in &self.non_main_fns {
-                diag.span_note(span, rustc_errors::fluent::here_is_main);
+                diag.span_note(span, fluent::passes_here_is_main);
             }
-            diag.note(rustc_errors::fluent::one_or_more_possible_main);
-            diag.help(rustc_errors::fluent::consider_moving_main);
+            diag.note(fluent::passes_one_or_more_possible_main);
+            diag.help(fluent::passes_consider_moving_main);
             // There were some functions named `main` though. Try to give the user a hint.
-            rustc_errors::fluent::main_must_be_defined_at_crate
+            fluent::passes_main_must_be_defined_at_crate
         } else if self.has_filename {
-            rustc_errors::fluent::consider_adding_main_to_file
+            fluent::passes_consider_adding_main_to_file
         } else {
-            rustc_errors::fluent::consider_adding_main_at_crate
+            fluent::passes_consider_adding_main_at_crate
         };
         if self.file_empty {
             diag.note(note);
@@ -1208,11 +1209,11 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
 
         if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){
             // There is something at `crate::main`, but it is not a function definition.
-            diag.span_label(main_def.span, rustc_errors::fluent::non_function_main);
+            diag.span_label(main_def.span, fluent::passes_non_function_main);
         }
 
         if self.add_teach_note {
-            diag.note(rustc_errors::fluent::teach_note);
+            diag.note(fluent::passes_teach_note);
         }
         diag
     }
@@ -1241,12 +1242,9 @@ impl IntoDiagnostic<'_> for DuplicateLangItem {
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag = handler.struct_err_with_code(
             match self.duplicate {
-                Duplicate::Plain => rustc_errors::fluent::passes_duplicate_lang_item,
-
-                Duplicate::Crate => rustc_errors::fluent::passes_duplicate_lang_item_crate,
-                Duplicate::CrateDepends => {
-                    rustc_errors::fluent::passes_duplicate_lang_item_crate_depends
-                }
+                Duplicate::Plain => fluent::passes_duplicate_lang_item,
+                Duplicate::Crate => fluent::passes_duplicate_lang_item_crate,
+                Duplicate::CrateDepends => fluent::passes_duplicate_lang_item_crate_depends,
             },
             error_code!(E0152),
         );
@@ -1261,24 +1259,24 @@ impl IntoDiagnostic<'_> for DuplicateLangItem {
             diag.set_span(span);
         }
         if let Some(span) = self.first_defined_span {
-            diag.span_note(span, rustc_errors::fluent::first_defined_span);
+            diag.span_note(span, fluent::passes_first_defined_span);
         } else {
             if self.orig_dependency_of.is_empty() {
-                diag.note(rustc_errors::fluent::first_defined_crate);
+                diag.note(fluent::passes_first_defined_crate);
             } else {
-                diag.note(rustc_errors::fluent::first_defined_crate_depends);
+                diag.note(fluent::passes_first_defined_crate_depends);
             }
 
             if self.orig_is_local {
-                diag.note(rustc_errors::fluent::first_definition_local);
+                diag.note(fluent::passes_first_definition_local);
             } else {
-                diag.note(rustc_errors::fluent::first_definition_path);
+                diag.note(fluent::passes_first_definition_path);
             }
 
             if self.is_local {
-                diag.note(rustc_errors::fluent::second_definition_local);
+                diag.note(fluent::passes_second_definition_local);
             } else {
-                diag.note(rustc_errors::fluent::second_definition_path);
+                diag.note(fluent::passes_second_definition_path);
             }
         }
         diag
@@ -1389,7 +1387,7 @@ pub struct UselessStability {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(item)]
+    #[label(passes_item)]
     pub item_sp: Span,
 }
 
@@ -1399,7 +1397,7 @@ pub struct InvalidStability {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(item)]
+    #[label(passes_item)]
     pub item_sp: Span,
 }
 
@@ -1409,7 +1407,7 @@ pub struct CannotStabilizeDeprecated {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(item)]
+    #[label(passes_item)]
     pub item_sp: Span,
 }
 
@@ -1419,7 +1417,7 @@ pub struct InvalidDeprecationVersion {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(item)]
+    #[label(passes_item)]
     pub item_sp: Span,
 }
 
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 6e621b7eb5eb0..0cb8424082c3e 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -18,6 +18,8 @@ extern crate rustc_middle;
 #[macro_use]
 extern crate tracing;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
 use rustc_middle::ty::query::Providers;
 
 mod check_attr;
@@ -40,6 +42,8 @@ pub mod stability;
 mod upvars;
 mod weak_lang_items;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub fn provide(providers: &mut Providers) {
     check_attr::provide(providers);
     check_const::provide(providers);
diff --git a/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl b/compiler/rustc_plugin_impl/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl
rename to compiler/rustc_plugin_impl/locales/en-US.ftl
diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
index 9ac27c65da82e..3f03eef9ee320 100644
--- a/compiler/rustc_plugin_impl/src/lib.rs
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -11,11 +11,15 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_lint::LintStore;
+use rustc_macros::fluent_messages;
 
 mod errors;
 pub mod load;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 /// Structure used to register plugins.
 ///
 /// A plugin registrar function takes an `&mut Registry` and should call
diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_privacy/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/privacy.ftl
rename to compiler/rustc_privacy/locales/en-US.ftl
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index a6c95f1a815ac..72b53eefa0817 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -57,7 +57,7 @@ pub struct InPublicInterfaceTraits<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
     pub descr: DiagnosticArgFromDisplay<'a>,
-    #[label(visibility_label)]
+    #[label(privacy_visibility_label)]
     pub vis_span: Span,
 }
 
@@ -71,7 +71,7 @@ pub struct InPublicInterface<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
     pub descr: DiagnosticArgFromDisplay<'a>,
-    #[label(visibility_label)]
+    #[label(privacy_visibility_label)]
     pub vis_span: Span,
 }
 
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 58dfca75c65f7..9e856bb8a084e 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -16,11 +16,13 @@ use rustc_ast::MacroDef;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
+use rustc_macros::fluent_messages;
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
@@ -44,6 +46,8 @@ use errors::{
     UnnamedItemIsPrivate,
 };
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 ////////////////////////////////////////////////////////////////////////////////
 /// Generic infrastructure used to implement specific visitors below.
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_error_messages/locales/en-US/query_system.ftl b/compiler/rustc_query_system/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/query_system.ftl
rename to compiler/rustc_query_system/locales/en-US.ftl
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 623be668464e8..6cc4c9a7e1ef0 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -15,6 +15,9 @@ extern crate rustc_data_structures;
 #[macro_use]
 extern crate rustc_macros;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 pub mod cache;
 pub mod dep_graph;
 mod error;
@@ -26,3 +29,5 @@ pub use error::HandleCycleError;
 pub use error::LayoutOfDepth;
 pub use error::QueryOverflow;
 pub use values::Value;
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_error_messages/locales/en-US/resolve.ftl b/compiler/rustc_resolve/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/resolve.ftl
rename to compiler/rustc_resolve/locales/en-US.ftl
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 2c442774667b2..867363f4246af 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -38,7 +38,7 @@ pub(crate) struct NameAlreadyUsedInParameterList {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
-    #[label(first_use_of_name)]
+    #[label(resolve_first_use_of_name)]
     pub(crate) first_use_span: Span,
     pub(crate) name: Symbol,
 }
@@ -121,7 +121,7 @@ pub(crate) struct VariableBoundWithDifferentMode {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
-    #[label(first_binding_span)]
+    #[label(resolve_first_binding_span)]
     pub(crate) first_binding_span: Span,
     pub(crate) variable_name: Symbol,
 }
@@ -293,7 +293,7 @@ pub(crate) struct BindingShadowsSomethingUnacceptable<'a> {
     pub(crate) article: &'a str,
     #[subdiagnostic]
     pub(crate) sub_suggestion: Option<BindingShadowsSomethingUnacceptableSuggestion>,
-    #[label(label_shadowed_binding)]
+    #[label(resolve_label_shadowed_binding)]
     pub(crate) shadowed_binding_span: Span,
     pub(crate) participle: &'a str,
     pub(crate) name: Symbol,
@@ -369,7 +369,7 @@ pub(crate) struct UnreachableLabel {
     #[label]
     pub(crate) span: Span,
     pub(crate) name: Symbol,
-    #[label(label_definition_span)]
+    #[label(resolve_label_definition_span)]
     pub(crate) definition_span: Span,
     #[subdiagnostic]
     pub(crate) sub_suggestion: Option<UnreachableLabelSubSuggestion>,
@@ -413,7 +413,7 @@ pub(crate) struct TraitImplMismatch {
     pub(crate) span: Span,
     pub(crate) name: Symbol,
     pub(crate) kind: String,
-    #[label(label_trait_item)]
+    #[label(resolve_label_trait_item)]
     pub(crate) trait_item_span: Span,
     pub(crate) trait_path: String,
     pub(crate) code: String,
@@ -434,9 +434,9 @@ pub(crate) struct TraitImplDuplicate {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
-    #[label(old_span_label)]
+    #[label(resolve_old_span_label)]
     pub(crate) old_span: Span,
-    #[label(trait_item_span)]
+    #[label(resolve_trait_item_span)]
     pub(crate) trait_item_span: Span,
     pub(crate) name: Symbol,
 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 66034baaa0b6b..d36ee369b434d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -28,7 +28,9 @@ use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArg
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::{Lrc, MappedReadGuard};
-use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{
+    Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage,
+};
 use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS};
@@ -37,6 +39,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::TraitCandidate;
 use rustc_index::vec::IndexVec;
+use rustc_macros::fluent_messages;
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
@@ -77,6 +80,8 @@ mod late;
 mod macros;
 pub mod rustdoc;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 enum Weak {
     Yes,
     No,
diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_session/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/session.ftl
rename to compiler/rustc_session/locales/en-US.ftl
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 39e871f532c49..e1f1a5f6d2e00 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -18,6 +18,9 @@ pub mod errors;
 #[macro_use]
 extern crate tracing;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 pub mod cgu_reuse_tracker;
 pub mod utils;
 pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass};
@@ -39,6 +42,8 @@ pub mod output;
 
 pub use getopts;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
 /// instead of implementing everything in `rustc_middle`.
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index cbdcc5581e5ee..4e8c3f73e29cd 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -226,8 +226,8 @@ pub struct ParseSess {
 
 impl ParseSess {
     /// Used for testing.
-    pub fn new(file_path_mapping: FilePathMapping) -> Self {
-        let fallback_bundle = fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+    pub fn new(locale_resources: Vec<&'static str>, file_path_mapping: FilePathMapping) -> Self {
+        let fallback_bundle = fallback_fluent_bundle(locale_resources, false);
         let sm = Lrc::new(SourceMap::new(file_path_mapping));
         let handler = Handler::with_tty_emitter(
             ColorConfig::Auto,
@@ -265,7 +265,7 @@ impl ParseSess {
     }
 
     pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
-        let fallback_bundle = fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+        let fallback_bundle = fallback_fluent_bundle(Vec::new(), false);
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         let fatal_handler =
             Handler::with_tty_emitter(ColorConfig::Auto, false, None, None, None, fallback_bundle);
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 3dc09854b3cbc..446ba63ed1c86 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1341,6 +1341,7 @@ pub fn build_session(
     io: CompilerIO,
     bundle: Option<Lrc<rustc_errors::FluentBundle>>,
     registry: rustc_errors::registry::Registry,
+    fluent_resources: Vec<&'static str>,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     target_override: Option<Target>,
@@ -1385,7 +1386,7 @@ pub fn build_session(
     ));
 
     let fallback_bundle = fallback_fluent_bundle(
-        rustc_errors::DEFAULT_LOCALE_RESOURCES,
+        fluent_resources,
         sopts.unstable_opts.translate_directionality_markers,
     );
     let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
@@ -1630,7 +1631,10 @@ pub enum IncrCompSession {
 }
 
 fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler {
-    let fallback_bundle = fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+    // FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will
+    // need to reference every crate that might emit an early error for translation to work.
+    let fallback_bundle =
+        fallback_fluent_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false);
     let emitter: Box<dyn Emitter + sync::Send> = match output {
         config::ErrorOutputType::HumanReadable(kind) => {
             let (short, color_config) = kind.unzip();
diff --git a/compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl b/compiler/rustc_symbol_mangling/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/symbol_mangling.ftl
rename to compiler/rustc_symbol_mangling/locales/en-US.ftl
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index d81722e59a66e..d9ce737348373 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -100,8 +100,10 @@ extern crate rustc_middle;
 #[macro_use]
 extern crate tracing;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_macros::fluent_messages;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
@@ -117,6 +119,8 @@ pub mod errors;
 pub mod test;
 pub mod typeid;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 /// This function computes the symbol name for the given `instance` and the
 /// given instantiating crate. That is, if you know that instance X is
 /// instantiated in crate Y, this is the symbol name this instance would have.
diff --git a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl b/compiler/rustc_trait_selection/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/trait_selection.ftl
rename to compiler/rustc_trait_selection/locales/en-US.ftl
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 4405537c645a9..df7c4df1868c7 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,4 +1,5 @@
-use rustc_errors::{fluent, ErrorGuaranteed, Handler, IntoDiagnostic};
+use crate::fluent_generated as fluent;
+use rustc_errors::{ErrorGuaranteed, Handler, IntoDiagnostic};
 use rustc_macros::Diagnostic;
 use rustc_middle::ty::{self, PolyTraitRef, Ty};
 use rustc_span::{Span, Symbol};
@@ -69,19 +70,19 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
         diag.code(rustc_errors::error_code!(E0751));
         match self.negative_impl_span {
             Ok(span) => {
-                diag.span_label(span, fluent::negative_implementation_here);
+                diag.span_label(span, fluent::trait_selection_negative_implementation_here);
             }
             Err(cname) => {
-                diag.note(fluent::negative_implementation_in_crate);
+                diag.note(fluent::trait_selection_negative_implementation_in_crate);
                 diag.set_arg("negative_impl_cname", cname.to_string());
             }
         }
         match self.positive_impl_span {
             Ok(span) => {
-                diag.span_label(span, fluent::positive_implementation_here);
+                diag.span_label(span, fluent::trait_selection_positive_implementation_here);
             }
             Err(cname) => {
-                diag.note(fluent::positive_implementation_in_crate);
+                diag.note(fluent::trait_selection_positive_implementation_in_crate);
                 diag.set_arg("positive_impl_cname", cname.to_string());
             }
         }
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 6fa0941036390..548b42cef430a 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -36,7 +36,12 @@ extern crate rustc_middle;
 #[macro_use]
 extern crate smallvec;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
+
 pub mod errors;
 pub mod infer;
 pub mod solve;
 pub mod traits;
+
+fluent_messages! { "../locales/en-US.ftl" }
diff --git a/compiler/rustc_error_messages/locales/en-US/ty_utils.ftl b/compiler/rustc_ty_utils/locales/en-US.ftl
similarity index 100%
rename from compiler/rustc_error_messages/locales/en-US/ty_utils.ftl
rename to compiler/rustc_ty_utils/locales/en-US.ftl
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index c05eeb353a848..ab3e62f048453 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -16,7 +16,7 @@ pub struct NeedsDropOverflow<'tcx> {
 pub struct GenericConstantTooComplex {
     #[primary_span]
     pub span: Span,
-    #[note(maybe_supported)]
+    #[note(ty_utils_maybe_supported)]
     pub maybe_supported: Option<()>,
     #[subdiagnostic]
     pub sub: GenericConstantTooComplexSub,
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 0853de601b040..35f468aa95280 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -15,6 +15,8 @@ extern crate rustc_middle;
 #[macro_use]
 extern crate tracing;
 
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::fluent_messages;
 use rustc_middle::ty::query::Providers;
 
 mod abi;
@@ -31,6 +33,8 @@ pub mod representability;
 mod structural_match;
 mod ty;
 
+fluent_messages! { "../locales/en-US.ftl" }
+
 pub fn provide(providers: &mut Providers) {
     abi::provide(providers);
     assoc::provide(providers);
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
index ed7683e36fd30..ef38ca3c16c1a 100644
--- a/src/librustdoc/clean/render_macro_matchers.rs
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -63,7 +63,8 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String
     let snippet = source_map.span_to_snippet(span).ok()?;
 
     // Create a Parser.
-    let sess = ParseSess::new(FilePathMapping::empty());
+    let sess =
+        ParseSess::new(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), FilePathMapping::empty());
     let file_name = source_map.span_to_filename(span);
     let mut parser =
         match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 5ab7056be442a..fbfc58a436b9b 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -115,8 +115,10 @@ pub(crate) fn new_handler(
     diagnostic_width: Option<usize>,
     unstable_opts: &UnstableOptions,
 ) -> rustc_errors::Handler {
-    let fallback_bundle =
-        rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+    let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+        rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
+        false,
+    );
     let emitter: Box<dyn Emitter + sync::Send> = match error_format {
         ErrorOutputType::HumanReadable(kind) => {
             let (short, color_config) = kind.unzip();
@@ -254,6 +256,7 @@ pub(crate) fn create_config(
         output_file: None,
         output_dir: None,
         file_loader: None,
+        locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES,
         lint_caps,
         parse_sess_created: None,
         register_lints: Some(Box::new(crate::lint::register_lints)),
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 0eba81c7c1ee3..8a73d25d3f000 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -96,6 +96,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         output_file: None,
         output_dir: None,
         file_loader: None,
+        locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES,
         lint_caps,
         parse_sess_created: None,
         register_lints: Some(Box::new(crate::lint::register_lints)),
@@ -545,8 +546,10 @@ pub(crate) fn make_test(
             // Any errors in parsing should also appear when the doctest is compiled for real, so just
             // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr.
             let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-            let fallback_bundle =
-                rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+            let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+                rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
+                false,
+            );
             supports_color = EmitterWriter::stderr(
                 ColorConfig::Auto,
                 None,
@@ -741,8 +744,10 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
             // Any errors in parsing should also appear when the doctest is compiled for real, so just
             // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr.
             let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-            let fallback_bundle =
-                rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+            let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+                rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
+                false,
+            );
 
             let emitter = EmitterWriter::new(
                 Box::new(io::sink()),
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index 03be5e7997167..26fbb03a43e69 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -33,8 +33,10 @@ fn check_rust_syntax(
     code_block: RustCodeBlock,
 ) {
     let buffer = Lrc::new(Lock::new(Buffer::default()));
-    let fallback_bundle =
-        rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+    let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+        rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
+        false,
+    );
     let emitter = BufferEmitter { buffer: Lrc::clone(&buffer), fallback_bundle };
 
     let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 0b31e20fc87c0..6fdb7de25ccc0 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -704,8 +704,10 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
                 let filename = FileName::anon_source_code(&code);
 
                 let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-                let fallback_bundle =
-                    rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+                let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+                    rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
+                    false
+                );
                 let emitter = EmitterWriter::new(
                     Box::new(io::sink()),
                     None,
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index e45835efe7464..9ac849aecf1a7 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -209,7 +209,10 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     // Separate the output with an empty line
     eprintln!();
 
-    let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+    let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+        rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
+        false
+    );
     let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
         rustc_errors::ColorConfig::Auto,
         None,
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 9014026b0aa4a..a64963db6a7d0 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -123,8 +123,10 @@ fn default_handler(
     let emitter = if hide_parse_errors {
         silent_emitter()
     } else {
-        let fallback_bundle =
-            rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+        let fallback_bundle = rustc_errors::fallback_fluent_bundle(
+            rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
+            false,
+        );
         Box::new(EmitterWriter::stderr(
             color_cfg,
             Some(source_map.clone()),
diff --git a/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
index 3aa57d58908bb..8dac53c2a6234 100644
--- a/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
+++ b/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
@@ -27,6 +27,8 @@ use std::any::Any;
 struct TheBackend;
 
 impl CodegenBackend for TheBackend {
+    fn locale_resource(&self) -> &'static str { "" }
+
     fn codegen_crate<'a, 'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs
index 5bb38fc02af91..53ec79e477bd4 100644
--- a/tests/run-make-fulldeps/issue-19371/foo.rs
+++ b/tests/run-make-fulldeps/issue-19371/foo.rs
@@ -53,6 +53,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         output_file: Some(output),
         output_dir: None,
         file_loader: None,
+        locale_resources: &[],
         lint_caps: Default::default(),
         parse_sess_created: None,
         register_lints: None,
diff --git a/tests/run-make/translation/Makefile b/tests/run-make/translation/Makefile
index 20e86c7f9a072..5b0b331ca468c 100644
--- a/tests/run-make/translation/Makefile
+++ b/tests/run-make/translation/Makefile
@@ -6,8 +6,10 @@ include ../../run-make-fulldeps/tools.mk
 
 SYSROOT:=$(shell $(RUSTC) --print sysroot)
 FAKEROOT=$(TMPDIR)/fakeroot
+RUSTC_LOG:=rustc_error_messages
+export RUSTC_TRANSLATION_NO_DEBUG_ASSERT:=1
 
-all: normal custom sysroot
+all: normal custom missing broken sysroot sysroot-invalid sysroot-missing
 
 # Check that the test works normally, using the built-in fallback bundle.
 normal: test.rs
@@ -32,6 +34,7 @@ broken: test.rs broken.ftl
 # identifier by making a local copy of the sysroot and adding the custom locale
 # to it.
 sysroot: test.rs working.ftl
+	rm -rf $(FAKEROOT)
 	mkdir $(FAKEROOT)
 	ln -s $(SYSROOT)/* $(FAKEROOT)
 	rm -f $(FAKEROOT)/lib
@@ -51,12 +54,12 @@ sysroot: test.rs working.ftl
 # found. This test might start failing if there actually exists a Klingon
 # translation of rustc's error messages.
 sysroot-missing: 
-	$(RUSTC) $< -Ztranslate-lang=tlh 2>&1 || grep "missing locale directory"
+	$(RUSTC) $< -Ztranslate-lang=tlh 2>&1 | grep "missing locale directory"
 
-# Check that the compiler errors out when the sysroot requested cannot be
-# found. This test might start failing if there actually exists a Klingon
-# translation of rustc's error messages.
+# Check that the compiler errors out when the directory for the locale in the
+# sysroot is actually a file.
 sysroot-invalid: test.rs working.ftl
+	rm -rf $(FAKEROOT)
 	mkdir $(FAKEROOT)
 	ln -s $(SYSROOT)/* $(FAKEROOT)
 	rm -f $(FAKEROOT)/lib
@@ -68,5 +71,6 @@ sysroot-invalid: test.rs working.ftl
 	rm -f $(FAKEROOT)/lib/rustlib/src
 	mkdir $(FAKEROOT)/lib/rustlib/src
 	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
-	touch $(FAKEROOT)/share/locale/zh-CN/
-	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 || grep "`\$sysroot/share/locales/\$locale` is not a directory"
+	mkdir -p $(FAKEROOT)/share/locale
+	touch $(FAKEROOT)/share/locale/zh-CN
+	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "`\$sysroot/share/locales/\$locale` is not a directory"
diff --git a/tests/ui-fulldeps/fluent-messages/duplicate.ftl b/tests/ui-fulldeps/fluent-messages/duplicate.ftl
new file mode 100644
index 0000000000000..871550b231a32
--- /dev/null
+++ b/tests/ui-fulldeps/fluent-messages/duplicate.ftl
@@ -0,0 +1,3 @@
+no_crate_a_b_key = Value
+
+no_crate_a_b_key = Another Value
diff --git a/tests/ui-fulldeps/fluent-messages/label-with-hyphens.ftl b/tests/ui-fulldeps/fluent-messages/label-with-hyphens.ftl
index 016cbeef662c7..3088b1f8dc832 100644
--- a/tests/ui-fulldeps/fluent-messages/label-with-hyphens.ftl
+++ b/tests/ui-fulldeps/fluent-messages/label-with-hyphens.ftl
@@ -1,2 +1,2 @@
-label_with_hyphens_some_slug = hi
+no_crate_some_slug = hi
     .label-has-hyphens = test
diff --git a/tests/ui-fulldeps/fluent-messages/missing-crate-name.ftl b/tests/ui-fulldeps/fluent-messages/missing-crate-name.ftl
index 9bd035c1bbac6..0a64e3894bd51 100644
--- a/tests/ui-fulldeps/fluent-messages/missing-crate-name.ftl
+++ b/tests/ui-fulldeps/fluent-messages/missing-crate-name.ftl
@@ -1,2 +1,2 @@
 with-hyphens = 1234
-test-crate_foo = abcd
+no-crate_foo = abcd
diff --git a/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl b/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl
index 0cd8229b23010..4c6514a977005 100644
--- a/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl
+++ b/tests/ui-fulldeps/fluent-messages/missing-message-ref.ftl
@@ -1 +1 @@
-missing_message_ref = {message}
+no_crate_missing_message_ref = {message}
diff --git a/tests/ui-fulldeps/fluent-messages/missing-message.ftl b/tests/ui-fulldeps/fluent-messages/missing-message.ftl
index 74b2aa1d44d1f..61f56fd4d57b6 100644
--- a/tests/ui-fulldeps/fluent-messages/missing-message.ftl
+++ b/tests/ui-fulldeps/fluent-messages/missing-message.ftl
@@ -1 +1 @@
-missing_message =
+no_crate_missing_message =
diff --git a/tests/ui-fulldeps/fluent-messages/slug-with-hyphens.ftl b/tests/ui-fulldeps/fluent-messages/slug-with-hyphens.ftl
index 86ba9a268f3f5..a64c85094f1d8 100644
--- a/tests/ui-fulldeps/fluent-messages/slug-with-hyphens.ftl
+++ b/tests/ui-fulldeps/fluent-messages/slug-with-hyphens.ftl
@@ -1 +1 @@
-slug_with_hyphens_this-slug-has-hyphens = hi
+no_crate_this-slug-has-hyphens = hi
diff --git a/tests/ui-fulldeps/fluent-messages/test.rs b/tests/ui-fulldeps/fluent-messages/test.rs
index 74303e97dba94..66575eb8e30cf 100644
--- a/tests/ui-fulldeps/fluent-messages/test.rs
+++ b/tests/ui-fulldeps/fluent-messages/test.rs
@@ -21,87 +21,74 @@ pub enum SubdiagnosticMessage {
 mod missing_absolute {
     use super::fluent_messages;
 
-    fluent_messages! {
-        missing_absolute => "/definitely_does_not_exist.ftl",
-//~^ ERROR could not open Fluent resource
-    }
+    fluent_messages! { "/definitely_does_not_exist.ftl" }
+    //~^ ERROR could not open Fluent resource
 }
 
 mod missing_relative {
     use super::fluent_messages;
 
-    fluent_messages! {
-        missing_relative => "../definitely_does_not_exist.ftl",
-//~^ ERROR could not open Fluent resource
-    }
+    fluent_messages! { "../definitely_does_not_exist.ftl" }
+    //~^ ERROR could not open Fluent resource
 }
 
 mod missing_message {
     use super::fluent_messages;
 
-    fluent_messages! {
-        missing_message => "./missing-message.ftl",
-//~^ ERROR could not parse Fluent resource
-    }
+    fluent_messages! { "./missing-message.ftl" }
+    //~^ ERROR could not parse Fluent resource
 }
 
 mod duplicate {
     use super::fluent_messages;
 
-    fluent_messages! {
-//~^ ERROR the name `a_b_key` is defined multiple times
-        a => "./duplicate-a.ftl",
-        a_b => "./duplicate-a-b.ftl",
-//~^ ERROR overrides existing message: `a_b_key`
-    }
+    fluent_messages! { "./duplicate.ftl" }
+    //~^ ERROR overrides existing message: `no_crate_a_b_key`
 }
 
 mod slug_with_hyphens {
     use super::fluent_messages;
 
-    fluent_messages! {
-        slug_with_hyphens => "./slug-with-hyphens.ftl",
-//~^ ERROR name `slug_with_hyphens_this-slug-has-hyphens` contains a '-' character
-    }
+    fluent_messages! { "./slug-with-hyphens.ftl" }
+    //~^ ERROR name `no_crate_this-slug-has-hyphens` contains a '-' character
 }
 
 mod label_with_hyphens {
     use super::fluent_messages;
 
-    fluent_messages! {
-        label_with_hyphens => "./label-with-hyphens.ftl",
-//~^ ERROR attribute `label-has-hyphens` contains a '-' character
-    }
+    fluent_messages! { "./label-with-hyphens.ftl" }
+    //~^ ERROR attribute `label-has-hyphens` contains a '-' character
 }
 
 mod valid {
     use super::fluent_messages;
 
-    fluent_messages! {
-        valid => "./valid.ftl",
-    }
+    fluent_messages! { "./valid.ftl" }
 
-    use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, valid_key};
+    mod test_generated {
+        use super::{fluent_generated::no_crate_key, DEFAULT_LOCALE_RESOURCE};
+    }
 }
 
 mod missing_crate_name {
     use super::fluent_messages;
 
-    fluent_messages! {
-        test_crate => "./missing-crate-name.ftl",
-//~^ ERROR name `test-crate_foo` contains a '-' character
-//~| ERROR name `with-hyphens` contains a '-' character
-//~| ERROR name `with-hyphens` does not start with the crate name
-    }
+    fluent_messages! { "./missing-crate-name.ftl" }
+    //~^ ERROR name `no-crate_foo` contains a '-' character
+    //~| ERROR name `with-hyphens` contains a '-' character
+    //~| ERROR name `with-hyphens` does not start with the crate name
 
-    use self::fluent_generated::{DEFAULT_LOCALE_RESOURCES, test_crate_foo, with_hyphens};
+    mod test_generated {
+        use super::{
+            fluent_generated::{no_crate_foo, with_hyphens},
+            DEFAULT_LOCALE_RESOURCE,
+        };
+    }
 }
 
 mod missing_message_ref {
     use super::fluent_messages;
 
-    fluent_messages! {
-        missing => "./missing-message-ref.ftl"
-//~^ ERROR referenced message `message` does not exist
-    }
+    fluent_messages! { "./missing-message-ref.ftl" }
+    //~^ ERROR referenced message `message` does not exist
 }
diff --git a/tests/ui-fulldeps/fluent-messages/test.stderr b/tests/ui-fulldeps/fluent-messages/test.stderr
index 2631b0a623275..c7961ed22f2b4 100644
--- a/tests/ui-fulldeps/fluent-messages/test.stderr
+++ b/tests/ui-fulldeps/fluent-messages/test.stderr
@@ -1,106 +1,87 @@
 error: could not open Fluent resource
-  --> $DIR/test.rs:25:29
+  --> $DIR/test.rs:24:24
    |
-LL |         missing_absolute => "/definitely_does_not_exist.ftl",
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "/definitely_does_not_exist.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: os-specific message
 
 error: could not open Fluent resource
-  --> $DIR/test.rs:34:29
+  --> $DIR/test.rs:31:24
    |
-LL |         missing_relative => "../definitely_does_not_exist.ftl",
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "../definitely_does_not_exist.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: os-specific message
 
 error: could not parse Fluent resource
-  --> $DIR/test.rs:43:28
+  --> $DIR/test.rs:38:24
    |
-LL |         missing_message => "./missing-message.ftl",
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "./missing-message.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: see additional errors emitted
 
-error: expected a message field for "missing_message"
+error: expected a message field for "no_crate_missing_message"
  --> ./missing-message.ftl:1:1
   |
-1 | missing_message =
-  | ^^^^^^^^^^^^^^^^^
+1 | no_crate_missing_message =
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
 
-error: overrides existing message: `a_b_key`
-  --> $DIR/test.rs:54:16
+error: overrides existing message: `no_crate_a_b_key`
+  --> $DIR/test.rs:45:24
    |
-LL |         a_b => "./duplicate-a-b.ftl",
-   |                ^^^^^^^^^^^^^^^^^^^^^
-   |
-help: previously defined in this resource
-  --> $DIR/test.rs:53:14
-   |
-LL |         a => "./duplicate-a.ftl",
-   |              ^^^^^^^^^^^^^^^^^^^
-
-error[E0428]: the name `a_b_key` is defined multiple times
-  --> $DIR/test.rs:51:5
-   |
-LL |     fluent_messages! {
-   |     ^^^^^^^^^^^^^^^^
-   |     |
-   |     `a_b_key` redefined here
-   |     previous definition of the value `a_b_key` here
-   |
-   = note: os-specific message
-   = note: os-specific message
+LL |     fluent_messages! { "./duplicate.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^
 
-error: name `slug_with_hyphens_this-slug-has-hyphens` contains a '-' character
-  --> $DIR/test.rs:63:30
+error: name `no_crate_this-slug-has-hyphens` contains a '-' character
+  --> $DIR/test.rs:52:24
    |
-LL |         slug_with_hyphens => "./slug-with-hyphens.ftl",
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "./slug-with-hyphens.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: replace any '-'s with '_'s
 
 error: attribute `label-has-hyphens` contains a '-' character
-  --> $DIR/test.rs:72:31
+  --> $DIR/test.rs:59:24
    |
-LL |         label_with_hyphens => "./label-with-hyphens.ftl",
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "./label-with-hyphens.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: replace any '-'s with '_'s
 
 error: name `with-hyphens` contains a '-' character
-  --> $DIR/test.rs:91:23
+  --> $DIR/test.rs:76:24
    |
-LL |         test_crate => "./missing-crate-name.ftl",
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "./missing-crate-name.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: replace any '-'s with '_'s
 
 error: name `with-hyphens` does not start with the crate name
-  --> $DIR/test.rs:91:23
+  --> $DIR/test.rs:76:24
    |
-LL |         test_crate => "./missing-crate-name.ftl",
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "./missing-crate-name.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: prepend `test_crate_` to the slug name: `test_crate_with_hyphens`
+   = help: prepend `no_crate_` to the slug name: `no_crate_with_hyphens`
 
-error: name `test-crate_foo` contains a '-' character
-  --> $DIR/test.rs:91:23
+error: name `no-crate_foo` contains a '-' character
+  --> $DIR/test.rs:76:24
    |
-LL |         test_crate => "./missing-crate-name.ftl",
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "./missing-crate-name.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: replace any '-'s with '_'s
 
-error: referenced message `message` does not exist (in message `missing_message_ref`)
-  --> $DIR/test.rs:104:20
+error: referenced message `message` does not exist (in message `no_crate_missing_message_ref`)
+  --> $DIR/test.rs:92:24
    |
-LL |         missing => "./missing-message-ref.ftl"
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fluent_messages! { "./missing-message-ref.ftl" }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: you may have meant to use a variable reference (`{$message}`)
 
-error: aborting due to 11 previous errors
+error: aborting due to 10 previous errors
 
-For more information about this error, try `rustc --explain E0428`.
diff --git a/tests/ui-fulldeps/fluent-messages/valid.ftl b/tests/ui-fulldeps/fluent-messages/valid.ftl
index 549274306005c..598473adb680f 100644
--- a/tests/ui-fulldeps/fluent-messages/valid.ftl
+++ b/tests/ui-fulldeps/fluent-messages/valid.ftl
@@ -1 +1 @@
-valid_key = Valid!
+no_crate_key = Valid!
diff --git a/compiler/rustc_error_messages/locales/en-US/compiletest.ftl b/tests/ui-fulldeps/internal-lints/diagnostics.ftl
similarity index 62%
rename from compiler/rustc_error_messages/locales/en-US/compiletest.ftl
rename to tests/ui-fulldeps/internal-lints/diagnostics.ftl
index 55061fbce7e4a..cb2d476d815d2 100644
--- a/compiler/rustc_error_messages/locales/en-US/compiletest.ftl
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.ftl
@@ -1,4 +1,4 @@
-compiletest_example = this is an example message used in testing
+no_crate_example = this is an example message used in testing
     .note = with a note
     .help = with a help
     .suggestion = with a suggestion
diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs
index 643e81d99c6a6..3aa65d53d4eae 100644
--- a/tests/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs
@@ -13,20 +13,22 @@ extern crate rustc_span;
 
 use rustc_errors::{
     AddToDiagnostic, IntoDiagnostic, Diagnostic, DiagnosticBuilder,
-    ErrorGuaranteed, Handler, fluent, SubdiagnosticMessage,
+    ErrorGuaranteed, Handler, DiagnosticMessage, SubdiagnosticMessage,
 };
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{fluent_messages, Diagnostic, Subdiagnostic};
 use rustc_span::Span;
 
+fluent_messages! { "./diagnostics.ftl" }
+
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct DeriveDiagnostic {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[note(compiletest_example)]
+#[note(no_crate_example)]
 struct Note {
     #[primary_span]
     span: Span,
@@ -45,7 +47,7 @@ pub struct TranslatableInIntoDiagnostic;
 
 impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for TranslatableInIntoDiagnostic {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        handler.struct_err(fluent::compiletest_example)
+        handler.struct_err(crate::fluent_generated::no_crate_example)
     }
 }
 
@@ -68,12 +70,12 @@ impl AddToDiagnostic for TranslatableInAddToDiagnostic {
     where
         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
     {
-        diag.note(fluent::note);
+        diag.note(crate::fluent_generated::no_crate_note);
     }
 }
 
 pub fn make_diagnostics<'a>(handler: &'a Handler) {
-    let _diag = handler.struct_err(fluent::compiletest_example);
+    let _diag = handler.struct_err(crate::fluent_generated::no_crate_example);
     //~^ ERROR diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
 
     let _diag = handler.struct_err("untranslatable diagnostic");
diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr
index 510d6a1710870..6f797ebc2dde4 100644
--- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr
@@ -1,5 +1,5 @@
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:39:17
+  --> $DIR/diagnostics.rs:41:17
    |
 LL |         handler.struct_err("untranslatable diagnostic")
    |                 ^^^^^^^^^^
@@ -11,15 +11,15 @@ LL | #![deny(rustc::untranslatable_diagnostic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:59:14
+  --> $DIR/diagnostics.rs:61:14
    |
 LL |         diag.note("untranslatable diagnostic");
    |              ^^^^
 
 error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
-  --> $DIR/diagnostics.rs:76:25
+  --> $DIR/diagnostics.rs:78:25
    |
-LL |     let _diag = handler.struct_err(fluent::compiletest_example);
+LL |     let _diag = handler.struct_err(crate::fluent_generated::no_crate_example);
    |                         ^^^^^^^^^^
    |
 note: the lint level is defined here
@@ -29,13 +29,13 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
-  --> $DIR/diagnostics.rs:79:25
+  --> $DIR/diagnostics.rs:81:25
    |
 LL |     let _diag = handler.struct_err("untranslatable diagnostic");
    |                         ^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:79:25
+  --> $DIR/diagnostics.rs:81:25
    |
 LL |     let _diag = handler.struct_err("untranslatable diagnostic");
    |                         ^^^^^^^^^^
diff --git a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs
index bdfd9628c4801..ddc86c1dc3129 100644
--- a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs
+++ b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs
@@ -31,7 +31,10 @@ pub fn main() {
 }
 
 fn parse() {
-    let parse_session = ParseSess::new(FilePathMapping::empty());
+    let parse_session = ParseSess::new(
+        vec![rustc_parse::DEFAULT_LOCALE_RESOURCE],
+        FilePathMapping::empty()
+    );
 
     let path = Path::new(file!());
     let path = path.canonicalize().unwrap();
diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
index a4fad9d3e1ec0..e417a6a833b72 100644
--- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -220,7 +220,7 @@ fn main() {
 }
 
 fn run() {
-    let ps = ParseSess::new(FilePathMapping::empty());
+    let ps = ParseSess::new(vec![rustc_parse::DEFAULT_LOCALE_RESOURCE], FilePathMapping::empty());
 
     iter_exprs(2, &mut |mut e| {
         // If the pretty printer is correct, then `parse(print(e))` should be identical to `e`,
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 07f95d13937b4..01e6434b07567 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -17,26 +17,28 @@ use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
 extern crate rustc_macros;
-use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_macros::{fluent_messages, Diagnostic, LintDiagnostic, Subdiagnostic};
 
 extern crate rustc_middle;
 use rustc_middle::ty::Ty;
 
 extern crate rustc_errors;
-use rustc_errors::{Applicability, MultiSpan};
+use rustc_errors::{Applicability, DiagnosticMessage, MultiSpan, SubdiagnosticMessage};
 
 extern crate rustc_session;
 
+fluent_messages! { "./example.ftl" }
+
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct Hello {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct HelloWarn {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 //~^ ERROR unsupported type attribute for diagnostic derive enum
 enum DiagnosticOnEnum {
     Foo,
@@ -46,13 +48,13 @@ enum DiagnosticOnEnum {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 #[diag = "E0123"]
 //~^ ERROR `#[diag = ...]` is not a valid attribute
 struct WrongStructAttrStyle {}
 
 #[derive(Diagnostic)]
-#[nonsense(compiletest_example, code = "E0123")]
+#[nonsense(no_crate_example, code = "E0123")]
 //~^ ERROR `#[nonsense(...)]` is not a valid attribute
 //~^^ ERROR diagnostic slug not specified
 //~^^^ ERROR cannot find attribute `nonsense` in this scope
@@ -66,7 +68,7 @@ struct InvalidLitNestedAttr {}
 
 #[derive(Diagnostic)]
 #[diag(nonsense, code = "E0123")]
-//~^ ERROR cannot find value `nonsense` in module `rustc_errors::fluent`
+//~^ ERROR cannot find value `nonsense` in module `crate::fluent_generated`
 struct InvalidNestedStructAttr {}
 
 #[derive(Diagnostic)]
@@ -90,12 +92,12 @@ struct InvalidNestedStructAttr2 {}
 struct InvalidNestedStructAttr3 {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123", slug = "foo")]
+#[diag(no_crate_example, code = "E0123", slug = "foo")]
 //~^ ERROR `#[diag(slug = ...)]` is not a valid attribute
 struct InvalidNestedStructAttr4 {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct WrongPlaceField {
     #[suggestion = "bar"]
     //~^ ERROR `#[suggestion = ...]` is not a valid attribute
@@ -103,20 +105,20 @@ struct WrongPlaceField {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
-#[diag(compiletest_example, code = "E0456")]
+#[diag(no_crate_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0456")]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
 struct DiagSpecifiedTwice {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0456", code = "E0457")]
+#[diag(no_crate_example, code = "E0456", code = "E0457")]
 //~^ ERROR specified multiple times
 struct CodeSpecifiedTwice {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, compiletest_example, code = "E0456")]
-//~^ ERROR `#[diag(compiletest_example)]` is not a valid attribute
+#[diag(no_crate_example, no_crate::example, code = "E0456")]
+//~^ ERROR `#[diag(no_crate::example)]` is not a valid attribute
 struct SlugSpecifiedTwice {}
 
 #[derive(Diagnostic)]
@@ -128,11 +130,11 @@ struct KindNotProvided {} //~ ERROR diagnostic slug not specified
 struct SlugNotProvided {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct CodeNotProvided {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct MessageWrongType {
     #[primary_span]
     //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
@@ -140,7 +142,7 @@ struct MessageWrongType {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct InvalidPathFieldAttr {
     #[nonsense]
     //~^ ERROR `#[nonsense]` is not a valid attribute
@@ -149,34 +151,34 @@ struct InvalidPathFieldAttr {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithField {
     name: String,
-    #[label(label)]
+    #[label(no_crate_label)]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithMessageAppliedToField {
-    #[label(label)]
+    #[label(no_crate_label)]
     //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
     name: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithNonexistentField {
-    #[suggestion(suggestion, code = "{name}")]
+    #[suggestion(no_crate_suggestion, code = "{name}")]
     //~^ ERROR `name` doesn't refer to a field on this type
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
 //~^ ERROR invalid format string: expected `'}'`
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorMissingClosingBrace {
-    #[suggestion(suggestion, code = "{name")]
+    #[suggestion(no_crate_suggestion, code = "{name")]
     suggestion: (Span, Applicability),
     name: String,
     val: usize,
@@ -184,50 +186,50 @@ struct ErrorMissingClosingBrace {
 
 #[derive(Diagnostic)]
 //~^ ERROR invalid format string: unmatched `}`
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorMissingOpeningBrace {
-    #[suggestion(suggestion, code = "name}")]
+    #[suggestion(no_crate_suggestion, code = "name}")]
     suggestion: (Span, Applicability),
     name: String,
     val: usize,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct LabelOnSpan {
-    #[label(label)]
+    #[label(no_crate_label)]
     sp: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct LabelOnNonSpan {
-    #[label(label)]
+    #[label(no_crate_label)]
     //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
     id: u32,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct Suggest {
-    #[suggestion(suggestion, code = "This is the suggested code")]
-    #[suggestion(suggestion, code = "This is the suggested code", style = "normal")]
-    #[suggestion(suggestion, code = "This is the suggested code", style = "short")]
-    #[suggestion(suggestion, code = "This is the suggested code", style = "hidden")]
-    #[suggestion(suggestion, code = "This is the suggested code", style = "verbose")]
+    #[suggestion(no_crate_suggestion, code = "This is the suggested code")]
+    #[suggestion(no_crate_suggestion, code = "This is the suggested code", style = "normal")]
+    #[suggestion(no_crate_suggestion, code = "This is the suggested code", style = "short")]
+    #[suggestion(no_crate_suggestion, code = "This is the suggested code", style = "hidden")]
+    #[suggestion(no_crate_suggestion, code = "This is the suggested code", style = "verbose")]
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithoutCode {
-    #[suggestion(suggestion)]
+    #[suggestion(no_crate_suggestion)]
     //~^ ERROR suggestion without `code = "..."`
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithBadKey {
     #[suggestion(nonsense = "bar")]
     //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute
@@ -236,7 +238,7 @@ struct SuggestWithBadKey {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithShorthandMsg {
     #[suggestion(msg = "bar")]
     //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute
@@ -245,52 +247,52 @@ struct SuggestWithShorthandMsg {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithoutMsg {
     #[suggestion(code = "bar")]
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithTypesSwapped {
-    #[suggestion(suggestion, code = "This is suggested code")]
+    #[suggestion(no_crate_suggestion, code = "This is suggested code")]
     suggestion: (Applicability, Span),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithWrongTypeApplicabilityOnly {
-    #[suggestion(suggestion, code = "This is suggested code")]
+    #[suggestion(no_crate_suggestion, code = "This is suggested code")]
     //~^ ERROR wrong field type for suggestion
     suggestion: Applicability,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithSpanOnly {
-    #[suggestion(suggestion, code = "This is suggested code")]
+    #[suggestion(no_crate_suggestion, code = "This is suggested code")]
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithDuplicateSpanAndApplicability {
-    #[suggestion(suggestion, code = "This is suggested code")]
+    #[suggestion(no_crate_suggestion, code = "This is suggested code")]
     suggestion: (Span, Span, Applicability),
     //~^ ERROR specified multiple times
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct SuggestWithDuplicateApplicabilityAndSpan {
-    #[suggestion(suggestion, code = "This is suggested code")]
+    #[suggestion(no_crate_suggestion, code = "This is suggested code")]
     suggestion: (Applicability, Applicability, Span),
     //~^ ERROR specified multiple times
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct WrongKindOfAnnotation {
     #[label = "bar"]
     //~^ ERROR `#[label = ...]` is not a valid attribute
@@ -298,38 +300,38 @@ struct WrongKindOfAnnotation {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct OptionsInErrors {
-    #[label(label)]
+    #[label(no_crate_label)]
     label: Option<Span>,
-    #[suggestion(suggestion, code = "...")]
+    #[suggestion(no_crate_suggestion, code = "...")]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0456")]
+#[diag(no_crate_example, code = "E0456")]
 struct MoveOutOfBorrowError<'tcx> {
     name: Ident,
     ty: Ty<'tcx>,
     #[primary_span]
-    #[label(label)]
+    #[label(no_crate_label)]
     span: Span,
-    #[label(label)]
+    #[label(no_crate_label)]
     other_span: Span,
-    #[suggestion(suggestion, code = "{name}.clone()")]
+    #[suggestion(no_crate_suggestion, code = "{name}.clone()")]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithLifetime<'a> {
-    #[label(label)]
+    #[label(no_crate_label)]
     span: Span,
     name: &'a str,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithDefaultLabelAttr<'a> {
     #[label]
     span: Span,
@@ -338,7 +340,7 @@ struct ErrorWithDefaultLabelAttr<'a> {
 
 #[derive(Diagnostic)]
 //~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ArgFieldWithoutSkip {
     #[primary_span]
     span: Span,
@@ -346,7 +348,7 @@ struct ArgFieldWithoutSkip {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ArgFieldWithSkip {
     #[primary_span]
     span: Span,
@@ -357,132 +359,132 @@ struct ArgFieldWithSkip {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithSpannedNote {
     #[note]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithSpannedNoteCustom {
-    #[note(note)]
+    #[note(no_crate_note)]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 #[note]
 struct ErrorWithNote {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
-#[note(note)]
+#[diag(no_crate_example, code = "E0123")]
+#[note(no_crate_note)]
 struct ErrorWithNoteCustom {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithSpannedHelp {
     #[help]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithSpannedHelpCustom {
-    #[help(help)]
+    #[help(no_crate_help)]
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 #[help]
 struct ErrorWithHelp {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
-#[help(help)]
+#[diag(no_crate_example, code = "E0123")]
+#[help(no_crate_help)]
 struct ErrorWithHelpCustom {
     val: String,
 }
 
 #[derive(Diagnostic)]
 #[help]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithHelpWrongOrder {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[help(help)]
-#[diag(compiletest_example, code = "E0123")]
+#[help(no_crate_help)]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithHelpCustomWrongOrder {
     val: String,
 }
 
 #[derive(Diagnostic)]
 #[note]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithNoteWrongOrder {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[note(note)]
-#[diag(compiletest_example, code = "E0123")]
+#[note(no_crate_note)]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithNoteCustomWrongOrder {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ApplicabilityInBoth {
-    #[suggestion(suggestion, code = "...", applicability = "maybe-incorrect")]
+    #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")]
     //~^ ERROR specified multiple times
     suggestion: (Span, Applicability),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct InvalidApplicability {
-    #[suggestion(suggestion, code = "...", applicability = "batman")]
+    #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
     //~^ ERROR invalid applicability
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ValidApplicability {
-    #[suggestion(suggestion, code = "...", applicability = "maybe-incorrect")]
+    #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")]
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct NoApplicability {
-    #[suggestion(suggestion, code = "...")]
+    #[suggestion(no_crate_suggestion, code = "...")]
     suggestion: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[note(parse_add_paren)]
+#[note(no_crate_example)]
 struct Note;
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct Subdiagnostic {
     #[subdiagnostic]
     note: Note,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct VecField {
     #[primary_span]
     #[label]
@@ -490,57 +492,57 @@ struct VecField {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct UnitField {
     #[primary_span]
     spans: Span,
     #[help]
     foo: (),
-    #[help(help)]
+    #[help(no_crate_help)]
     bar: (),
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct OptUnitField {
     #[primary_span]
     spans: Span,
     #[help]
     foo: Option<()>,
-    #[help(help)]
+    #[help(no_crate_help)]
     bar: Option<()>,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct LabelWithTrailingPath {
-    #[label(label, foo)]
+    #[label(no_crate_label, foo)]
     //~^ ERROR `#[label(foo)]` is not a valid attribute
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct LabelWithTrailingNameValue {
-    #[label(label, foo = "...")]
+    #[label(no_crate_label, foo = "...")]
     //~^ ERROR `#[label(foo = ...)]` is not a valid attribute
     span: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct LabelWithTrailingList {
-    #[label(label, foo("..."))]
+    #[label(no_crate_label, foo("..."))]
     //~^ ERROR `#[label(foo(...))]` is not a valid attribute
     span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct LintsGood {}
 
 #[derive(LintDiagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct PrimarySpanOnLint {
     #[primary_span]
     //~^ ERROR `#[primary_span]` is not a valid attribute
@@ -548,42 +550,42 @@ struct PrimarySpanOnLint {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct ErrorWithMultiSpan {
     #[primary_span]
     span: MultiSpan,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 #[warning]
 struct ErrorWithWarn {
     val: String,
 }
 
 #[derive(Diagnostic)]
-#[error(compiletest_example, code = "E0123")]
+#[error(no_crate_example, code = "E0123")]
 //~^ ERROR `#[error(...)]` is not a valid attribute
 //~| ERROR diagnostic slug not specified
 //~| ERROR cannot find attribute `error` in this scope
 struct ErrorAttribute {}
 
 #[derive(Diagnostic)]
-#[warn_(compiletest_example, code = "E0123")]
+#[warn_(no_crate_example, code = "E0123")]
 //~^ ERROR `#[warn_(...)]` is not a valid attribute
 //~| ERROR diagnostic slug not specified
 //~| ERROR cannot find attribute `warn_` in this scope
 struct WarnAttribute {}
 
 #[derive(Diagnostic)]
-#[lint(compiletest_example, code = "E0123")]
+#[lint(no_crate_example, code = "E0123")]
 //~^ ERROR `#[lint(...)]` is not a valid attribute
 //~| ERROR diagnostic slug not specified
 //~| ERROR cannot find attribute `lint` in this scope
 struct LintAttributeOnSessionDiag {}
 
 #[derive(LintDiagnostic)]
-#[lint(compiletest_example, code = "E0123")]
+#[lint(no_crate_example, code = "E0123")]
 //~^ ERROR `#[lint(...)]` is not a valid attribute
 //~| ERROR `#[lint(...)]` is not a valid attribute
 //~| ERROR diagnostic slug not specified
@@ -591,55 +593,55 @@ struct LintAttributeOnSessionDiag {}
 struct LintAttributeOnLintDiag {}
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct DuplicatedSuggestionCode {
-    #[suggestion(suggestion, code = "...", code = ",,,")]
+    #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
     //~^ ERROR specified multiple times
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct InvalidTypeInSuggestionTuple {
-    #[suggestion(suggestion, code = "...")]
+    #[suggestion(no_crate_suggestion, code = "...")]
     suggestion: (Span, usize),
     //~^ ERROR wrong types for suggestion
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct MissingApplicabilityInSuggestionTuple {
-    #[suggestion(suggestion, code = "...")]
+    #[suggestion(no_crate_suggestion, code = "...")]
     suggestion: (Span,),
     //~^ ERROR wrong types for suggestion
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct MissingCodeInSuggestion {
-    #[suggestion(suggestion)]
+    #[suggestion(no_crate_suggestion)]
     //~^ ERROR suggestion without `code = "..."`
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
-#[multipart_suggestion(suggestion)]
+#[diag(no_crate_example, code = "E0123")]
+#[multipart_suggestion(no_crate_suggestion)]
 //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
 //~| ERROR cannot find attribute `multipart_suggestion` in this scope
 #[multipart_suggestion()]
 //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
 //~| ERROR cannot find attribute `multipart_suggestion` in this scope
 struct MultipartSuggestion {
-    #[multipart_suggestion(suggestion)]
+    #[multipart_suggestion(no_crate_suggestion)]
     //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute
     //~| ERROR cannot find attribute `multipart_suggestion` in this scope
     suggestion: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
-#[suggestion(suggestion, code = "...")]
+#[diag(no_crate_example, code = "E0123")]
+#[suggestion(no_crate_suggestion, code = "...")]
 //~^ ERROR `#[suggestion(...)]` is not a valid attribute
 struct SuggestionOnStruct {
     #[primary_span]
@@ -647,7 +649,7 @@ struct SuggestionOnStruct {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 #[label]
 //~^ ERROR `#[label]` is not a valid attribute
 struct LabelOnStruct {
@@ -657,30 +659,30 @@ struct LabelOnStruct {
 
 #[derive(Diagnostic)]
 enum ExampleEnum {
-    #[diag(compiletest_example)]
+    #[diag(no_crate_example)]
     Foo {
         #[primary_span]
         sp: Span,
         #[note]
         note_sp: Span,
     },
-    #[diag(compiletest_example)]
+    #[diag(no_crate_example)]
     Bar {
         #[primary_span]
         sp: Span,
     },
-    #[diag(compiletest_example)]
+    #[diag(no_crate_example)]
     Baz,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct RawIdentDiagnosticArg {
     pub r#type: String,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SubdiagnosticBad {
     #[subdiagnostic(bad)]
     //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
@@ -688,7 +690,7 @@ struct SubdiagnosticBad {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SubdiagnosticBadStr {
     #[subdiagnostic = "bad"]
     //~^ ERROR `#[subdiagnostic = ...]` is not a valid attribute
@@ -696,7 +698,7 @@ struct SubdiagnosticBadStr {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SubdiagnosticBadTwice {
     #[subdiagnostic(bad, bad)]
     //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
@@ -704,7 +706,7 @@ struct SubdiagnosticBadTwice {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SubdiagnosticBadLitStr {
     #[subdiagnostic("bad")]
     //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
@@ -712,7 +714,7 @@ struct SubdiagnosticBadLitStr {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SubdiagnosticEagerLint {
     #[subdiagnostic(eager)]
     //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
@@ -720,7 +722,7 @@ struct SubdiagnosticEagerLint {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SubdiagnosticEagerCorrect {
     #[subdiagnostic(eager)]
     note: Note,
@@ -731,7 +733,7 @@ struct SubdiagnosticEagerCorrect {
 // after the `span_suggestion` call - which breaks eager translation.
 
 #[derive(Subdiagnostic)]
-#[suggestion(use_instead, applicability = "machine-applicable", code = "{correct}")]
+#[suggestion(no_crate_example, applicability = "machine-applicable", code = "{correct}")]
 pub(crate) struct SubdiagnosticWithSuggestion {
     #[primary_span]
     span: Span,
@@ -740,7 +742,7 @@ pub(crate) struct SubdiagnosticWithSuggestion {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SubdiagnosticEagerSuggestion {
     #[subdiagnostic(eager)]
     sub: SubdiagnosticWithSuggestion,
@@ -748,7 +750,7 @@ struct SubdiagnosticEagerSuggestion {
 
 /// with a doc comment on the type..
 #[derive(Diagnostic)]
-#[diag(compiletest_example, code = "E0123")]
+#[diag(no_crate_example, code = "E0123")]
 struct WithDocComment {
     /// ..and the field
     #[primary_span]
@@ -756,21 +758,21 @@ struct WithDocComment {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SuggestionsGood {
     #[suggestion(code("foo", "bar"))]
     sub: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SuggestionsSingleItem {
     #[suggestion(code("foo"))]
     sub: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SuggestionsNoItem {
     #[suggestion(code())]
     //~^ ERROR expected at least one string literal for `code(...)`
@@ -778,7 +780,7 @@ struct SuggestionsNoItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SuggestionsInvalidItem {
     #[suggestion(code(foo))]
     //~^ ERROR `code(...)` must contain only string literals
@@ -786,7 +788,7 @@ struct SuggestionsInvalidItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SuggestionsInvalidLiteral {
     #[suggestion(code = 3)]
     //~^ ERROR `code = "..."`/`code(...)` must contain only string literals
@@ -794,16 +796,16 @@ struct SuggestionsInvalidLiteral {
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SuggestionStyleGood {
     #[suggestion(code = "", style = "hidden")]
     sub: Span,
 }
 
 #[derive(Diagnostic)]
-#[diag(compiletest_example)]
+#[diag(no_crate_example)]
 struct SuggestionOnVec {
-    #[suggestion(suggestion, code = "")]
+    #[suggestion(no_crate_suggestion, code = "")]
     //~^ ERROR `#[suggestion(...)]` is not a valid attribute
     sub: Vec<Span>,
 }
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 61806c80efc0b..fc0cd8419e440 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,11 +1,11 @@
 error: unsupported type attribute for diagnostic derive enum
-  --> $DIR/diagnostic-derive.rs:39:1
+  --> $DIR/diagnostic-derive.rs:41:1
    |
-LL | #[diag(compiletest_example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[diag(no_crate_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:42:5
+  --> $DIR/diagnostic-derive.rs:44:5
    |
 LL |     Foo,
    |     ^^^
@@ -13,7 +13,7 @@ LL |     Foo,
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:44:5
+  --> $DIR/diagnostic-derive.rs:46:5
    |
 LL |     Bar,
    |     ^^^
@@ -21,21 +21,21 @@ LL |     Bar,
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:50:1
+  --> $DIR/diagnostic-derive.rs:52:1
    |
 LL | #[diag = "E0123"]
    | ^^^^^^^^^^^^^^^^^
 
 error: `#[nonsense(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:55:1
+  --> $DIR/diagnostic-derive.rs:57:1
    |
-LL | #[nonsense(compiletest_example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[nonsense(no_crate_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:55:1
+  --> $DIR/diagnostic-derive.rs:57:1
    |
-LL | / #[nonsense(compiletest_example, code = "E0123")]
+LL | / #[nonsense(no_crate_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
@@ -45,7 +45,7 @@ LL | | struct InvalidStructAttr {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag("...")]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:62:8
+  --> $DIR/diagnostic-derive.rs:64:8
    |
 LL | #[diag("E0123")]
    |        ^^^^^^^
@@ -53,7 +53,7 @@ LL | #[diag("E0123")]
    = help: a diagnostic slug is required as the first argument
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:62:1
+  --> $DIR/diagnostic-derive.rs:64:1
    |
 LL | / #[diag("E0123")]
 LL | |
@@ -64,7 +64,7 @@ LL | | struct InvalidLitNestedAttr {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag(nonsense(...))]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:73:8
+  --> $DIR/diagnostic-derive.rs:75:8
    |
 LL | #[diag(nonsense("foo"), code = "E0123", slug = "foo")]
    |        ^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL | #[diag(nonsense("foo"), code = "E0123", slug = "foo")]
    = help: a diagnostic slug is required as the first argument
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:73:1
+  --> $DIR/diagnostic-derive.rs:75:1
    |
 LL | / #[diag(nonsense("foo"), code = "E0123", slug = "foo")]
 LL | |
@@ -83,7 +83,7 @@ LL | | struct InvalidNestedStructAttr1 {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:79:8
+  --> $DIR/diagnostic-derive.rs:81:8
    |
 LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")]
    |        ^^^^^^^^^^^^^^^^
@@ -91,7 +91,7 @@ LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")]
    = help: only `code` is a valid nested attributes following the slug
 
 error: `#[diag(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:79:42
+  --> $DIR/diagnostic-derive.rs:81:42
    |
 LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")]
    |                                          ^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")]
    = help: only `code` is a valid nested attributes following the slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:79:1
+  --> $DIR/diagnostic-derive.rs:81:1
    |
 LL | / #[diag(nonsense = "...", code = "E0123", slug = "foo")]
 LL | |
@@ -111,13 +111,13 @@ LL | | struct InvalidNestedStructAttr2 {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:86:8
+  --> $DIR/diagnostic-derive.rs:88:8
    |
 LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")]
    |        ^^^^^^^^^^^^
 
 error: `#[diag(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:86:38
+  --> $DIR/diagnostic-derive.rs:88:38
    |
 LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")]
    |                                      ^^^^^^^^^^^^
@@ -125,7 +125,7 @@ LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")]
    = help: only `code` is a valid nested attributes following the slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:86:1
+  --> $DIR/diagnostic-derive.rs:88:1
    |
 LL | / #[diag(nonsense = 4, code = "E0123", slug = "foo")]
 LL | |
@@ -137,65 +137,65 @@ LL | | struct InvalidNestedStructAttr3 {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[diag(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:93:45
+  --> $DIR/diagnostic-derive.rs:95:42
    |
-LL | #[diag(compiletest_example, code = "E0123", slug = "foo")]
-   |                                             ^^^^^^^^^^^^
+LL | #[diag(no_crate_example, code = "E0123", slug = "foo")]
+   |                                          ^^^^^^^^^^^^
    |
    = help: only `code` is a valid nested attributes following the slug
 
 error: `#[suggestion = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:100:5
+  --> $DIR/diagnostic-derive.rs:102:5
    |
 LL |     #[suggestion = "bar"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:107:8
+  --> $DIR/diagnostic-derive.rs:109:8
    |
-LL | #[diag(compiletest_example, code = "E0456")]
-   |        ^^^^^^^^^^^^^^^^^^^
+LL | #[diag(no_crate_example, code = "E0456")]
+   |        ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:106:8
+  --> $DIR/diagnostic-derive.rs:108:8
    |
-LL | #[diag(compiletest_example, code = "E0123")]
-   |        ^^^^^^^^^^^^^^^^^^^
+LL | #[diag(no_crate_example, code = "E0123")]
+   |        ^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:107:36
+  --> $DIR/diagnostic-derive.rs:109:33
    |
-LL | #[diag(compiletest_example, code = "E0456")]
-   |                                    ^^^^^^^
+LL | #[diag(no_crate_example, code = "E0456")]
+   |                                 ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:106:36
+  --> $DIR/diagnostic-derive.rs:108:33
    |
-LL | #[diag(compiletest_example, code = "E0123")]
-   |                                    ^^^^^^^
+LL | #[diag(no_crate_example, code = "E0123")]
+   |                                 ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:113:52
+  --> $DIR/diagnostic-derive.rs:115:49
    |
-LL | #[diag(compiletest_example, code = "E0456", code = "E0457")]
-   |                                                    ^^^^^^^
+LL | #[diag(no_crate_example, code = "E0456", code = "E0457")]
+   |                                                 ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:113:36
+  --> $DIR/diagnostic-derive.rs:115:33
    |
-LL | #[diag(compiletest_example, code = "E0456", code = "E0457")]
-   |                                    ^^^^^^^
+LL | #[diag(no_crate_example, code = "E0456", code = "E0457")]
+   |                                 ^^^^^^^
 
-error: `#[diag(compiletest_example)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:118:29
+error: `#[diag(no_crate::example)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:120:26
    |
-LL | #[diag(compiletest_example, compiletest_example, code = "E0456")]
-   |                             ^^^^^^^^^^^^^^^^^^^
+LL | #[diag(no_crate_example, no_crate::example, code = "E0456")]
+   |                          ^^^^^^^^^^^^^^^^^
    |
    = help: diagnostic slug must be the first argument
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:123:1
+  --> $DIR/diagnostic-derive.rs:125:1
    |
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -203,7 +203,7 @@ LL | struct KindNotProvided {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:126:1
+  --> $DIR/diagnostic-derive.rs:128:1
    |
 LL | / #[diag(code = "E0456")]
 LL | |
@@ -213,31 +213,31 @@ LL | | struct SlugNotProvided {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:137:5
+  --> $DIR/diagnostic-derive.rs:139:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: `#[nonsense]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:145:5
+  --> $DIR/diagnostic-derive.rs:147:5
    |
 LL |     #[nonsense]
    |     ^^^^^^^^^^^
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:162:5
+  --> $DIR/diagnostic-derive.rs:164:5
    |
-LL |     #[label(label)]
-   |     ^^^^^^^^^^^^^^^
+LL |     #[label(no_crate_label)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:170:37
+  --> $DIR/diagnostic-derive.rs:172:46
    |
-LL |     #[suggestion(suggestion, code = "{name}")]
-   |                                     ^^^^^^^^
+LL |     #[suggestion(no_crate_suggestion, code = "{name}")]
+   |                                              ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/diagnostic-derive.rs:175:10
+  --> $DIR/diagnostic-derive.rs:177:10
    |
 LL | #[derive(Diagnostic)]
    |          ^^^^^^^^^^ expected `'}'` in format string
@@ -246,7 +246,7 @@ LL | #[derive(Diagnostic)]
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
-  --> $DIR/diagnostic-derive.rs:185:10
+  --> $DIR/diagnostic-derive.rs:187:10
    |
 LL | #[derive(Diagnostic)]
    |          ^^^^^^^^^^ unmatched `}` in format string
@@ -255,19 +255,19 @@ LL | #[derive(Diagnostic)]
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/diagnostic-derive.rs:205:5
+  --> $DIR/diagnostic-derive.rs:207:5
    |
-LL |     #[label(label)]
-   |     ^^^^^^^^^^^^^^^
+LL |     #[label(no_crate_label)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:224:5
+  --> $DIR/diagnostic-derive.rs:226:5
    |
-LL |     #[suggestion(suggestion)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(no_crate_suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:232:18
+  --> $DIR/diagnostic-derive.rs:234:18
    |
 LL |     #[suggestion(nonsense = "bar")]
    |                  ^^^^^^^^^^^^^^^^
@@ -275,13 +275,13 @@ LL |     #[suggestion(nonsense = "bar")]
    = help: only `style`, `code` and `applicability` are valid nested attributes
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:232:5
+  --> $DIR/diagnostic-derive.rs:234:5
    |
 LL |     #[suggestion(nonsense = "bar")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(msg = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:241:18
+  --> $DIR/diagnostic-derive.rs:243:18
    |
 LL |     #[suggestion(msg = "bar")]
    |                  ^^^^^^^^^^^
@@ -289,15 +289,15 @@ LL |     #[suggestion(msg = "bar")]
    = help: only `style`, `code` and `applicability` are valid nested attributes
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:241:5
+  --> $DIR/diagnostic-derive.rs:243:5
    |
 LL |     #[suggestion(msg = "bar")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: wrong field type for suggestion
-  --> $DIR/diagnostic-derive.rs:264:5
+  --> $DIR/diagnostic-derive.rs:266:5
    |
-LL | /     #[suggestion(suggestion, code = "This is suggested code")]
+LL | /     #[suggestion(no_crate_suggestion, code = "This is suggested code")]
 LL | |
 LL | |     suggestion: Applicability,
    | |_____________________________^
@@ -305,75 +305,75 @@ LL | |     suggestion: Applicability,
    = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:280:24
+  --> $DIR/diagnostic-derive.rs:282:24
    |
 LL |     suggestion: (Span, Span, Applicability),
    |                        ^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:280:18
+  --> $DIR/diagnostic-derive.rs:282:18
    |
 LL |     suggestion: (Span, Span, Applicability),
    |                  ^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:288:33
+  --> $DIR/diagnostic-derive.rs:290:33
    |
 LL |     suggestion: (Applicability, Applicability, Span),
    |                                 ^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:288:18
+  --> $DIR/diagnostic-derive.rs:290:18
    |
 LL |     suggestion: (Applicability, Applicability, Span),
    |                  ^^^^^^^^^^^^^
 
 error: `#[label = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:295:5
+  --> $DIR/diagnostic-derive.rs:297:5
    |
 LL |     #[label = "bar"]
    |     ^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:446:44
+  --> $DIR/diagnostic-derive.rs:448:53
    |
-LL |     #[suggestion(suggestion, code = "...", applicability = "maybe-incorrect")]
-   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")]
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:448:24
+  --> $DIR/diagnostic-derive.rs:450:24
    |
 LL |     suggestion: (Span, Applicability),
    |                        ^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/diagnostic-derive.rs:454:44
+  --> $DIR/diagnostic-derive.rs:456:53
    |
-LL |     #[suggestion(suggestion, code = "...", applicability = "batman")]
-   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label(foo)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:517:20
+  --> $DIR/diagnostic-derive.rs:519:29
    |
-LL |     #[label(label, foo)]
-   |                    ^^^
+LL |     #[label(no_crate_label, foo)]
+   |                             ^^^
    |
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: `#[label(foo = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:525:20
+  --> $DIR/diagnostic-derive.rs:527:29
    |
-LL |     #[label(label, foo = "...")]
-   |                    ^^^^^^^^^^^
+LL |     #[label(no_crate_label, foo = "...")]
+   |                             ^^^^^^^^^^^
 
 error: `#[label(foo(...))]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:533:20
+  --> $DIR/diagnostic-derive.rs:535:29
    |
-LL |     #[label(label, foo("..."))]
-   |                    ^^^^^^^^^^
+LL |     #[label(no_crate_label, foo("..."))]
+   |                             ^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:545:5
+  --> $DIR/diagnostic-derive.rs:547:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -381,15 +381,15 @@ LL |     #[primary_span]
    = help: the `primary_span` field attribute is not valid for lint diagnostics
 
 error: `#[error(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:565:1
+  --> $DIR/diagnostic-derive.rs:567:1
    |
-LL | #[error(compiletest_example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[error(no_crate_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:565:1
+  --> $DIR/diagnostic-derive.rs:567:1
    |
-LL | / #[error(compiletest_example, code = "E0123")]
+LL | / #[error(no_crate_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
@@ -399,15 +399,15 @@ LL | | struct ErrorAttribute {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[warn_(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:572:1
+  --> $DIR/diagnostic-derive.rs:574:1
    |
-LL | #[warn_(compiletest_example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[warn_(no_crate_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:572:1
+  --> $DIR/diagnostic-derive.rs:574:1
    |
-LL | / #[warn_(compiletest_example, code = "E0123")]
+LL | / #[warn_(no_crate_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
@@ -417,15 +417,15 @@ LL | | struct WarnAttribute {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:579:1
+  --> $DIR/diagnostic-derive.rs:581:1
    |
-LL | #[lint(compiletest_example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[lint(no_crate_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:579:1
+  --> $DIR/diagnostic-derive.rs:581:1
    |
-LL | / #[lint(compiletest_example, code = "E0123")]
+LL | / #[lint(no_crate_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
@@ -435,21 +435,21 @@ LL | | struct LintAttributeOnSessionDiag {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:586:1
+  --> $DIR/diagnostic-derive.rs:588:1
    |
-LL | #[lint(compiletest_example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[lint(no_crate_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:586:1
+  --> $DIR/diagnostic-derive.rs:588:1
    |
-LL | #[lint(compiletest_example, code = "E0123")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[lint(no_crate_example, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:586:1
+  --> $DIR/diagnostic-derive.rs:588:1
    |
-LL | / #[lint(compiletest_example, code = "E0123")]
+LL | / #[lint(no_crate_example, code = "E0123")]
 LL | |
 LL | |
 LL | |
@@ -460,19 +460,19 @@ LL | | struct LintAttributeOnLintDiag {}
    = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]`
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:596:44
+  --> $DIR/diagnostic-derive.rs:598:53
    |
-LL |     #[suggestion(suggestion, code = "...", code = ",,,")]
-   |                                            ^^^^^^^^^^^^
+LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
+   |                                                     ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:596:30
+  --> $DIR/diagnostic-derive.rs:598:39
    |
-LL |     #[suggestion(suggestion, code = "...", code = ",,,")]
-   |                              ^^^^^^^^^^^^
+LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
+   |                                       ^^^^^^^^^^^^
 
 error: wrong types for suggestion
-  --> $DIR/diagnostic-derive.rs:605:24
+  --> $DIR/diagnostic-derive.rs:607:24
    |
 LL |     suggestion: (Span, usize),
    |                        ^^^^^
@@ -480,7 +480,7 @@ LL |     suggestion: (Span, usize),
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
 error: wrong types for suggestion
-  --> $DIR/diagnostic-derive.rs:613:17
+  --> $DIR/diagnostic-derive.rs:615:17
    |
 LL |     suggestion: (Span,),
    |                 ^^^^^^^
@@ -488,21 +488,21 @@ LL |     suggestion: (Span,),
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:620:5
+  --> $DIR/diagnostic-derive.rs:622:5
    |
-LL |     #[suggestion(suggestion)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(no_crate_suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:627:1
+  --> $DIR/diagnostic-derive.rs:629:1
    |
-LL | #[multipart_suggestion(suggestion)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[multipart_suggestion(no_crate_suggestion)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider creating a `Subdiagnostic` instead
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:630:1
+  --> $DIR/diagnostic-derive.rs:632:1
    |
 LL | #[multipart_suggestion()]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -510,23 +510,23 @@ LL | #[multipart_suggestion()]
    = help: consider creating a `Subdiagnostic` instead
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:634:5
+  --> $DIR/diagnostic-derive.rs:636:5
    |
-LL |     #[multipart_suggestion(suggestion)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[multipart_suggestion(no_crate_suggestion)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider creating a `Subdiagnostic` instead
 
 error: `#[suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:642:1
+  --> $DIR/diagnostic-derive.rs:644:1
    |
-LL | #[suggestion(suggestion, code = "...")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(no_crate_suggestion, code = "...")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
 error: `#[label]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:651:1
+  --> $DIR/diagnostic-derive.rs:653:1
    |
 LL | #[label]
    | ^^^^^^^^
@@ -534,7 +534,7 @@ LL | #[label]
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:685:5
+  --> $DIR/diagnostic-derive.rs:687:5
    |
 LL |     #[subdiagnostic(bad)]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -542,13 +542,13 @@ LL |     #[subdiagnostic(bad)]
    = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:693:5
+  --> $DIR/diagnostic-derive.rs:695:5
    |
 LL |     #[subdiagnostic = "bad"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:701:5
+  --> $DIR/diagnostic-derive.rs:703:5
    |
 LL |     #[subdiagnostic(bad, bad)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -556,7 +556,7 @@ LL |     #[subdiagnostic(bad, bad)]
    = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:709:5
+  --> $DIR/diagnostic-derive.rs:711:5
    |
 LL |     #[subdiagnostic("bad")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -564,7 +564,7 @@ LL |     #[subdiagnostic("bad")]
    = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:717:5
+  --> $DIR/diagnostic-derive.rs:719:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -572,95 +572,95 @@ LL |     #[subdiagnostic(eager)]
    = help: eager subdiagnostics are not supported on lints
 
 error: expected at least one string literal for `code(...)`
-  --> $DIR/diagnostic-derive.rs:775:18
+  --> $DIR/diagnostic-derive.rs:777:18
    |
 LL |     #[suggestion(code())]
    |                  ^^^^^^
 
 error: `code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:783:23
+  --> $DIR/diagnostic-derive.rs:785:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^
 
 error: `code = "..."`/`code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:791:18
+  --> $DIR/diagnostic-derive.rs:793:18
    |
 LL |     #[suggestion(code = 3)]
    |                  ^^^^^^^^
 
 error: `#[suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:806:5
+  --> $DIR/diagnostic-derive.rs:808:5
    |
-LL |     #[suggestion(suggestion, code = "")]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(no_crate_suggestion, code = "")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[suggestion(...)]` applied to `Vec` field is ambiguous
    = help: to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]`
    = help: to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]`
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:55:3
+  --> $DIR/diagnostic-derive.rs:57:3
    |
-LL | #[nonsense(compiletest_example, code = "E0123")]
+LL | #[nonsense(no_crate_example, code = "E0123")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:145:7
+  --> $DIR/diagnostic-derive.rs:147:7
    |
 LL |     #[nonsense]
    |       ^^^^^^^^
 
 error: cannot find attribute `error` in this scope
-  --> $DIR/diagnostic-derive.rs:565:3
+  --> $DIR/diagnostic-derive.rs:567:3
    |
-LL | #[error(compiletest_example, code = "E0123")]
+LL | #[error(no_crate_example, code = "E0123")]
    |   ^^^^^
 
 error: cannot find attribute `warn_` in this scope
-  --> $DIR/diagnostic-derive.rs:572:3
+  --> $DIR/diagnostic-derive.rs:574:3
    |
-LL | #[warn_(compiletest_example, code = "E0123")]
+LL | #[warn_(no_crate_example, code = "E0123")]
    |   ^^^^^ help: a built-in attribute with a similar name exists: `warn`
 
 error: cannot find attribute `lint` in this scope
-  --> $DIR/diagnostic-derive.rs:579:3
+  --> $DIR/diagnostic-derive.rs:581:3
    |
-LL | #[lint(compiletest_example, code = "E0123")]
+LL | #[lint(no_crate_example, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `lint` in this scope
-  --> $DIR/diagnostic-derive.rs:586:3
+  --> $DIR/diagnostic-derive.rs:588:3
    |
-LL | #[lint(compiletest_example, code = "E0123")]
+LL | #[lint(no_crate_example, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:627:3
+  --> $DIR/diagnostic-derive.rs:629:3
    |
-LL | #[multipart_suggestion(suggestion)]
+LL | #[multipart_suggestion(no_crate_suggestion)]
    |   ^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:630:3
+  --> $DIR/diagnostic-derive.rs:632:3
    |
 LL | #[multipart_suggestion()]
    |   ^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:634:7
+  --> $DIR/diagnostic-derive.rs:636:7
    |
-LL |     #[multipart_suggestion(suggestion)]
+LL |     #[multipart_suggestion(no_crate_suggestion)]
    |       ^^^^^^^^^^^^^^^^^^^^
 
-error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent`
-  --> $DIR/diagnostic-derive.rs:68:8
+error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated`
+  --> $DIR/diagnostic-derive.rs:70:8
    |
 LL | #[diag(nonsense, code = "E0123")]
-   |        ^^^^^^^^ not found in `rustc_errors::fluent`
+   |        ^^^^^^^^ not found in `crate::fluent_generated`
 
 error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-  --> $DIR/diagnostic-derive.rs:339:10
+  --> $DIR/diagnostic-derive.rs:341:10
    |
 LL | #[derive(Diagnostic)]
    |          ^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
diff --git a/tests/ui-fulldeps/session-diagnostic/example.ftl b/tests/ui-fulldeps/session-diagnostic/example.ftl
new file mode 100644
index 0000000000000..cb2d476d815d2
--- /dev/null
+++ b/tests/ui-fulldeps/session-diagnostic/example.ftl
@@ -0,0 +1,5 @@
+no_crate_example = this is an example message used in testing
+    .note = with a note
+    .help = with a help
+    .suggestion = with a suggestion
+    .label = with a label
diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index 09ad696490983..c882f7792d5bd 100644
--- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -15,12 +15,14 @@ extern crate rustc_macros;
 extern crate rustc_session;
 extern crate rustc_span;
 
-use rustc_errors::Applicability;
-use rustc_macros::Subdiagnostic;
+use rustc_errors::{Applicability, DiagnosticMessage, SubdiagnosticMessage};
+use rustc_macros::{fluent_messages, Subdiagnostic};
 use rustc_span::Span;
 
+fluent_messages! { "./example.ftl" }
+
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct A {
     #[primary_span]
     span: Span,
@@ -29,13 +31,13 @@ struct A {
 
 #[derive(Subdiagnostic)]
 enum B {
-    #[label(parse_add_paren)]
+    #[label(no_crate_example)]
     A {
         #[primary_span]
         span: Span,
         var: String,
     },
-    #[label(parse_add_paren)]
+    #[label(no_crate_example)]
     B {
         #[primary_span]
         span: Span,
@@ -44,7 +46,7 @@ enum B {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 //~^ ERROR label without `#[primary_span]` field
 struct C {
     var: String,
@@ -120,8 +122,8 @@ struct K {
 
 #[derive(Subdiagnostic)]
 #[label(slug)]
-//~^ ERROR cannot find value `slug` in module `rustc_errors::fluent`
-//~^^ NOTE not found in `rustc_errors::fluent`
+//~^ ERROR cannot find value `slug` in module `crate::fluent_generated`
+//~^^ NOTE not found in `crate::fluent_generated`
 struct L {
     #[primary_span]
     span: Span,
@@ -138,7 +140,7 @@ struct M {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren, code = "...")]
+#[label(no_crate_example, code = "...")]
 //~^ ERROR `#[label(code = ...)]` is not a valid attribute
 struct N {
     #[primary_span]
@@ -147,7 +149,7 @@ struct N {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren, applicability = "machine-applicable")]
+#[label(no_crate_example, applicability = "machine-applicable")]
 //~^ ERROR `#[label(applicability = ...)]` is not a valid attribute
 struct O {
     #[primary_span]
@@ -160,7 +162,7 @@ struct O {
 //~^ ERROR cannot find attribute `foo` in this scope
 //~^^ ERROR unsupported type attribute for subdiagnostic enum
 enum P {
-    #[label(parse_add_paren)]
+    #[label(no_crate_example)]
     A {
         #[primary_span]
         span: Span,
@@ -230,7 +232,7 @@ enum U {
 
 #[derive(Subdiagnostic)]
 enum V {
-    #[label(parse_add_paren)]
+    #[label(no_crate_example)]
     A {
         #[primary_span]
         span: Span,
@@ -244,7 +246,7 @@ enum V {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 //~^ ERROR label without `#[primary_span]` field
 struct W {
     #[primary_span]
@@ -253,7 +255,7 @@ struct W {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct X {
     #[primary_span]
     span: Span,
@@ -263,7 +265,7 @@ struct X {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct Y {
     #[primary_span]
     span: Span,
@@ -274,7 +276,7 @@ struct Y {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct Z {
     #[primary_span]
     span: Span,
@@ -285,7 +287,7 @@ struct Z {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct AA {
     #[primary_span]
     span: Span,
@@ -296,7 +298,7 @@ struct AA {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct AB {
     #[primary_span]
     span: Span,
@@ -312,23 +314,23 @@ union AC {
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
+#[label(no_crate_example)]
 struct AD {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren, parse_add_paren)]
-//~^ ERROR `#[label(parse_add_paren)]` is not a valid attribute
+#[label(no_crate_example, no_crate::example)]
+//~^ ERROR `#[label(no_crate::example)]` is not a valid attribute
 struct AE {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct AF {
     #[primary_span]
     //~^ NOTE previously specified here
@@ -346,7 +348,7 @@ struct AG {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...")]
+#[suggestion(no_crate_example, code = "...")]
 struct AH {
     #[primary_span]
     span: Span,
@@ -357,7 +359,7 @@ struct AH {
 
 #[derive(Subdiagnostic)]
 enum AI {
-    #[suggestion(parse_add_paren, code = "...")]
+    #[suggestion(no_crate_example, code = "...")]
     A {
         #[primary_span]
         span: Span,
@@ -365,7 +367,7 @@ enum AI {
         applicability: Applicability,
         var: String,
     },
-    #[suggestion(parse_add_paren, code = "...")]
+    #[suggestion(no_crate_example, code = "...")]
     B {
         #[primary_span]
         span: Span,
@@ -376,7 +378,7 @@ enum AI {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...", code = "...")]
+#[suggestion(no_crate_example, code = "...", code = "...")]
 //~^ ERROR specified multiple times
 //~^^ NOTE previously specified here
 struct AJ {
@@ -387,7 +389,7 @@ struct AJ {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...")]
+#[suggestion(no_crate_example, code = "...")]
 struct AK {
     #[primary_span]
     span: Span,
@@ -400,7 +402,7 @@ struct AK {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...")]
+#[suggestion(no_crate_example, code = "...")]
 struct AL {
     #[primary_span]
     span: Span,
@@ -410,14 +412,14 @@ struct AL {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...")]
+#[suggestion(no_crate_example, code = "...")]
 struct AM {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren)]
+#[suggestion(no_crate_example)]
 //~^ ERROR suggestion without `code = "..."`
 struct AN {
     #[primary_span]
@@ -427,7 +429,7 @@ struct AN {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...", applicability = "foo")]
+#[suggestion(no_crate_example, code = "...", applicability = "foo")]
 //~^ ERROR invalid applicability
 struct AO {
     #[primary_span]
@@ -435,24 +437,24 @@ struct AO {
 }
 
 #[derive(Subdiagnostic)]
-#[help(parse_add_paren)]
+#[help(no_crate_example)]
 struct AP {
     var: String,
 }
 
 #[derive(Subdiagnostic)]
-#[note(parse_add_paren)]
+#[note(no_crate_example)]
 struct AQ;
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...")]
+#[suggestion(no_crate_example, code = "...")]
 //~^ ERROR suggestion without `#[primary_span]` field
 struct AR {
     var: String,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...", applicability = "machine-applicable")]
+#[suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
 struct AS {
     #[primary_span]
     span: Span,
@@ -462,7 +464,7 @@ struct AS {
 #[label]
 //~^ ERROR unsupported type attribute for subdiagnostic enum
 enum AT {
-    #[label(parse_add_paren)]
+    #[label(no_crate_example)]
     A {
         #[primary_span]
         span: Span,
@@ -471,7 +473,7 @@ enum AT {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "{var}", applicability = "machine-applicable")]
+#[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
 struct AU {
     #[primary_span]
     span: Span,
@@ -479,7 +481,7 @@ struct AU {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "{var}", applicability = "machine-applicable")]
+#[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
 //~^ ERROR `var` doesn't refer to a field on this type
 struct AV {
     #[primary_span]
@@ -488,7 +490,7 @@ struct AV {
 
 #[derive(Subdiagnostic)]
 enum AW {
-    #[suggestion(parse_add_paren, code = "{var}", applicability = "machine-applicable")]
+    #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
     A {
         #[primary_span]
         span: Span,
@@ -498,7 +500,7 @@ enum AW {
 
 #[derive(Subdiagnostic)]
 enum AX {
-    #[suggestion(parse_add_paren, code = "{var}", applicability = "machine-applicable")]
+    #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
     //~^ ERROR `var` doesn't refer to a field on this type
     A {
         #[primary_span]
@@ -507,18 +509,18 @@ enum AX {
 }
 
 #[derive(Subdiagnostic)]
-#[warning(parse_add_paren)]
+#[warning(no_crate_example)]
 struct AY {}
 
 #[derive(Subdiagnostic)]
-#[warning(parse_add_paren)]
+#[warning(no_crate_example)]
 struct AZ {
     #[primary_span]
     span: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "...")]
+#[suggestion(no_crate_example, code = "...")]
 //~^ ERROR suggestion without `#[primary_span]` field
 struct BA {
     #[suggestion_part]
@@ -533,7 +535,7 @@ struct BA {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren, code = "...", applicability = "machine-applicable")]
+#[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
 //~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
 //~| ERROR `#[multipart_suggestion(code = ...)]` is not a valid attribute
 struct BBa {
@@ -541,7 +543,7 @@ struct BBa {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(no_crate_example, applicability = "machine-applicable")]
 struct BBb {
     #[suggestion_part]
     //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
@@ -549,7 +551,7 @@ struct BBb {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(no_crate_example, applicability = "machine-applicable")]
 struct BBc {
     #[suggestion_part()]
     //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
@@ -557,7 +559,7 @@ struct BBc {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren)]
+#[multipart_suggestion(no_crate_example)]
 //~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
 struct BC {
     #[primary_span]
@@ -566,7 +568,7 @@ struct BC {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren)]
+#[multipart_suggestion(no_crate_example)]
 struct BD {
     #[suggestion_part]
     //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
@@ -586,7 +588,7 @@ struct BD {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(no_crate_example, applicability = "machine-applicable")]
 struct BE {
     #[suggestion_part(code = "...", code = ",,,")]
     //~^ ERROR specified multiple times
@@ -595,7 +597,7 @@ struct BE {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(no_crate_example, applicability = "machine-applicable")]
 struct BF {
     #[suggestion_part(code = "(")]
     first: Span,
@@ -604,7 +606,7 @@ struct BF {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren)]
+#[multipart_suggestion(no_crate_example)]
 struct BG {
     #[applicability]
     appl: Applicability,
@@ -615,7 +617,7 @@ struct BG {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(no_crate_example, applicability = "machine-applicable")]
 struct BH {
     #[applicability]
     //~^ ERROR `#[applicability]` has no effect
@@ -627,14 +629,14 @@ struct BH {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")]
+#[multipart_suggestion(no_crate_example, applicability = "machine-applicable")]
 struct BI {
     #[suggestion_part(code = "")]
     spans: Vec<Span>,
 }
 
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct BJ {
     #[primary_span]
     span: Span,
@@ -643,7 +645,7 @@ struct BJ {
 
 /// with a doc comment on the type..
 #[derive(Subdiagnostic)]
-#[label(parse_add_paren)]
+#[label(no_crate_example)]
 struct BK {
     /// ..and the field
     #[primary_span]
@@ -654,7 +656,7 @@ struct BK {
 #[derive(Subdiagnostic)]
 enum BL {
     /// ..and the variant..
-    #[label(parse_add_paren)]
+    #[label(no_crate_example)]
     Foo {
         /// ..and the field
         #[primary_span]
@@ -663,7 +665,7 @@ enum BL {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren)]
+#[multipart_suggestion(no_crate_example)]
 struct BM {
     #[suggestion_part(code("foo"))]
     //~^ ERROR expected exactly one string literal for `code = ...`
@@ -672,7 +674,7 @@ struct BM {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren)]
+#[multipart_suggestion(no_crate_example)]
 struct BN {
     #[suggestion_part(code("foo", "bar"))]
     //~^ ERROR expected exactly one string literal for `code = ...`
@@ -681,7 +683,7 @@ struct BN {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren)]
+#[multipart_suggestion(no_crate_example)]
 struct BO {
     #[suggestion_part(code(3))]
     //~^ ERROR expected exactly one string literal for `code = ...`
@@ -690,7 +692,7 @@ struct BO {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren)]
+#[multipart_suggestion(no_crate_example)]
 struct BP {
     #[suggestion_part(code())]
     //~^ ERROR expected exactly one string literal for `code = ...`
@@ -699,7 +701,7 @@ struct BP {
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_add_paren)]
+#[multipart_suggestion(no_crate_example)]
 struct BQ {
     #[suggestion_part(code = 3)]
     //~^ ERROR `code = "..."`/`code(...)` must contain only string literals
@@ -708,42 +710,42 @@ struct BQ {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "")]
+#[suggestion(no_crate_example, code = "")]
 struct SuggestionStyleDefault {
     #[primary_span]
     sub: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style = "short")]
+#[suggestion(no_crate_example, code = "", style = "short")]
 struct SuggestionStyleShort {
     #[primary_span]
     sub: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style = "hidden")]
+#[suggestion(no_crate_example, code = "", style = "hidden")]
 struct SuggestionStyleHidden {
     #[primary_span]
     sub: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style = "verbose")]
+#[suggestion(no_crate_example, code = "", style = "verbose")]
 struct SuggestionStyleVerbose {
     #[primary_span]
     sub: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style = "tool-only")]
+#[suggestion(no_crate_example, code = "", style = "tool-only")]
 struct SuggestionStyleToolOnly {
     #[primary_span]
     sub: Span,
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style = "hidden", style = "normal")]
+#[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
 //~^ ERROR specified multiple times
 //~| NOTE previously specified here
 struct SuggestionStyleTwice {
@@ -752,7 +754,7 @@ struct SuggestionStyleTwice {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion_hidden(parse_add_paren, code = "")]
+#[suggestion_hidden(no_crate_example, code = "")]
 //~^ ERROR #[suggestion_hidden(...)]` is not a valid attribute
 struct SuggestionStyleOldSyntax {
     #[primary_span]
@@ -760,7 +762,7 @@ struct SuggestionStyleOldSyntax {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion_hidden(parse_add_paren, code = "", style = "normal")]
+#[suggestion_hidden(no_crate_example, code = "", style = "normal")]
 //~^ ERROR #[suggestion_hidden(...)]` is not a valid attribute
 struct SuggestionStyleOldAndNewSyntax {
     #[primary_span]
@@ -768,7 +770,7 @@ struct SuggestionStyleOldAndNewSyntax {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style = "foo")]
+#[suggestion(no_crate_example, code = "", style = "foo")]
 //~^ ERROR invalid suggestion style
 struct SuggestionStyleInvalid1 {
     #[primary_span]
@@ -776,7 +778,7 @@ struct SuggestionStyleInvalid1 {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style = 42)]
+#[suggestion(no_crate_example, code = "", style = 42)]
 //~^ ERROR `#[suggestion(style = ...)]` is not a valid attribute
 struct SuggestionStyleInvalid2 {
     #[primary_span]
@@ -784,7 +786,7 @@ struct SuggestionStyleInvalid2 {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style)]
+#[suggestion(no_crate_example, code = "", style)]
 //~^ ERROR `#[suggestion(style)]` is not a valid attribute
 struct SuggestionStyleInvalid3 {
     #[primary_span]
@@ -792,7 +794,7 @@ struct SuggestionStyleInvalid3 {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "", style("foo"))]
+#[suggestion(no_crate_example, code = "", style("foo"))]
 //~^ ERROR `#[suggestion(style(...))]` is not a valid attribute
 struct SuggestionStyleInvalid4 {
     #[primary_span]
@@ -800,7 +802,7 @@ struct SuggestionStyleInvalid4 {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_add_paren, code = "")]
+#[suggestion(no_crate_example, code = "")]
 //~^ ERROR suggestion without `#[primary_span]` field
 struct PrimarySpanOnVec {
     #[primary_span]
diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index f9d1a63031d7c..343134af6bc14 100644
--- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -1,7 +1,7 @@
 error: label without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:47:1
+  --> $DIR/subdiagnostic-derive.rs:49:1
    |
-LL | / #[label(parse_add_paren)]
+LL | / #[label(no_crate_example)]
 LL | |
 LL | | struct C {
 LL | |     var: String,
@@ -9,141 +9,141 @@ LL | | }
    | |_^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:54:1
+  --> $DIR/subdiagnostic-derive.rs:56:1
    |
 LL | #[label]
    | ^^^^^^^^
 
 error: `#[foo]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:63:1
+  --> $DIR/subdiagnostic-derive.rs:65:1
    |
 LL | #[foo]
    | ^^^^^^
 
 error: `#[label = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:73:1
+  --> $DIR/subdiagnostic-derive.rs:75:1
    |
 LL | #[label = "..."]
    | ^^^^^^^^^^^^^^^^
 
 error: `#[label(bug = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:82:9
+  --> $DIR/subdiagnostic-derive.rs:84:9
    |
 LL | #[label(bug = "...")]
    |         ^^^^^^^^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:82:1
+  --> $DIR/subdiagnostic-derive.rs:84:1
    |
 LL | #[label(bug = "...")]
    | ^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label("...")]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:92:9
+  --> $DIR/subdiagnostic-derive.rs:94:9
    |
 LL | #[label("...")]
    |         ^^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:92:1
+  --> $DIR/subdiagnostic-derive.rs:94:1
    |
 LL | #[label("...")]
    | ^^^^^^^^^^^^^^^
 
 error: `#[label(slug = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:102:9
+  --> $DIR/subdiagnostic-derive.rs:104:9
    |
 LL | #[label(slug = 4)]
    |         ^^^^^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:102:1
+  --> $DIR/subdiagnostic-derive.rs:104:1
    |
 LL | #[label(slug = 4)]
    | ^^^^^^^^^^^^^^^^^^
 
 error: `#[label(slug(...))]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:112:9
+  --> $DIR/subdiagnostic-derive.rs:114:9
    |
 LL | #[label(slug("..."))]
    |         ^^^^^^^^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:112:1
+  --> $DIR/subdiagnostic-derive.rs:114:1
    |
 LL | #[label(slug("..."))]
    | ^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:132:1
+  --> $DIR/subdiagnostic-derive.rs:134:1
    |
 LL | #[label()]
    | ^^^^^^^^^^
 
 error: `#[label(code = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:141:26
+  --> $DIR/subdiagnostic-derive.rs:143:27
    |
-LL | #[label(parse_add_paren, code = "...")]
-   |                          ^^^^^^^^^^^^
+LL | #[label(no_crate_example, code = "...")]
+   |                           ^^^^^^^^^^^^
 
 error: `#[label(applicability = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:150:26
+  --> $DIR/subdiagnostic-derive.rs:152:27
    |
-LL | #[label(parse_add_paren, applicability = "machine-applicable")]
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label(no_crate_example, applicability = "machine-applicable")]
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:159:1
+  --> $DIR/subdiagnostic-derive.rs:161:1
    |
 LL | #[foo]
    | ^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:173:5
+  --> $DIR/subdiagnostic-derive.rs:175:5
    |
 LL |     #[bar]
    |     ^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:185:5
+  --> $DIR/subdiagnostic-derive.rs:187:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:197:5
+  --> $DIR/subdiagnostic-derive.rs:199:5
    |
 LL |     #[bar = 4]
    |     ^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:209:5
+  --> $DIR/subdiagnostic-derive.rs:211:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
 
 error: `#[label(code = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:221:13
+  --> $DIR/subdiagnostic-derive.rs:223:13
    |
 LL |     #[label(code = "...")]
    |             ^^^^^^^^^^^^
 
 error: diagnostic slug must be first argument of a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:221:5
+  --> $DIR/subdiagnostic-derive.rs:223:5
    |
 LL |     #[label(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:250:5
+  --> $DIR/subdiagnostic-derive.rs:252:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: label without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:247:1
+  --> $DIR/subdiagnostic-derive.rs:249:1
    |
-LL | / #[label(parse_add_paren)]
+LL | / #[label(no_crate_example)]
 LL | |
 LL | | struct W {
 LL | |     #[primary_span]
@@ -153,13 +153,13 @@ LL | | }
    | |_^
 
 error: `#[applicability]` is only valid on suggestions
-  --> $DIR/subdiagnostic-derive.rs:260:5
+  --> $DIR/subdiagnostic-derive.rs:262:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:270:5
+  --> $DIR/subdiagnostic-derive.rs:272:5
    |
 LL |     #[bar]
    |     ^^^^^^
@@ -167,13 +167,13 @@ LL |     #[bar]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:281:5
+  --> $DIR/subdiagnostic-derive.rs:283:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:292:5
+  --> $DIR/subdiagnostic-derive.rs:294:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL |     #[bar("...")]
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
 error: unexpected unsupported untagged union
-  --> $DIR/subdiagnostic-derive.rs:308:1
+  --> $DIR/subdiagnostic-derive.rs:310:1
    |
 LL | / union AC {
 LL | |
@@ -190,78 +190,78 @@ LL | |     b: u64,
 LL | | }
    | |_^
 
-error: `#[label(parse_add_paren)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:323:26
+error: `#[label(no_crate::example)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:325:27
    |
-LL | #[label(parse_add_paren, parse_add_paren)]
-   |                          ^^^^^^^^^^^^^^^
+LL | #[label(no_crate_example, no_crate::example)]
+   |                           ^^^^^^^^^^^^^^^^^
    |
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:336:5
+  --> $DIR/subdiagnostic-derive.rs:338:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:333:5
+  --> $DIR/subdiagnostic-derive.rs:335:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:342:8
+  --> $DIR/subdiagnostic-derive.rs:344:8
    |
 LL | struct AG {
    |        ^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:379:45
+  --> $DIR/subdiagnostic-derive.rs:381:46
    |
-LL | #[suggestion(parse_add_paren, code = "...", code = "...")]
-   |                                             ^^^^^^^^^^^^
+LL | #[suggestion(no_crate_example, code = "...", code = "...")]
+   |                                              ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:379:31
+  --> $DIR/subdiagnostic-derive.rs:381:32
    |
-LL | #[suggestion(parse_add_paren, code = "...", code = "...")]
-   |                               ^^^^^^^^^^^^
+LL | #[suggestion(no_crate_example, code = "...", code = "...")]
+   |                                ^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:397:5
+  --> $DIR/subdiagnostic-derive.rs:399:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:394:5
+  --> $DIR/subdiagnostic-derive.rs:396:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
-  --> $DIR/subdiagnostic-derive.rs:407:5
+  --> $DIR/subdiagnostic-derive.rs:409:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: suggestion without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:420:1
+  --> $DIR/subdiagnostic-derive.rs:422:1
    |
-LL | #[suggestion(parse_add_paren)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(no_crate_example)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/subdiagnostic-derive.rs:430:45
+  --> $DIR/subdiagnostic-derive.rs:432:46
    |
-LL | #[suggestion(parse_add_paren, code = "...", applicability = "foo")]
-   |                                             ^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")]
+   |                                              ^^^^^^^^^^^^^^^^^^^^^
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:448:1
+  --> $DIR/subdiagnostic-derive.rs:450:1
    |
-LL | / #[suggestion(parse_add_paren, code = "...")]
+LL | / #[suggestion(no_crate_example, code = "...")]
 LL | |
 LL | | struct AR {
 LL | |     var: String,
@@ -269,25 +269,25 @@ LL | | }
    | |_^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:462:1
+  --> $DIR/subdiagnostic-derive.rs:464:1
    |
 LL | #[label]
    | ^^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:482:38
+  --> $DIR/subdiagnostic-derive.rs:484:39
    |
-LL | #[suggestion(parse_add_paren, code = "{var}", applicability = "machine-applicable")]
-   |                                      ^^^^^^^
+LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
+   |                                       ^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:501:42
+  --> $DIR/subdiagnostic-derive.rs:503:43
    |
-LL |     #[suggestion(parse_add_paren, code = "{var}", applicability = "machine-applicable")]
-   |                                          ^^^^^^^
+LL |     #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
+   |                                           ^^^^^^^
 
 error: `#[suggestion_part]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:524:5
+  --> $DIR/subdiagnostic-derive.rs:526:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
@@ -295,7 +295,7 @@ LL |     #[suggestion_part]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
 
 error: `#[suggestion_part(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:527:5
+  --> $DIR/subdiagnostic-derive.rs:529:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -303,9 +303,9 @@ LL |     #[suggestion_part(code = "...")]
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:521:1
+  --> $DIR/subdiagnostic-derive.rs:523:1
    |
-LL | / #[suggestion(parse_add_paren, code = "...")]
+LL | / #[suggestion(no_crate_example, code = "...")]
 LL | |
 LL | | struct BA {
 LL | |     #[suggestion_part]
@@ -315,17 +315,17 @@ LL | | }
    | |_^
 
 error: `#[multipart_suggestion(code = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:536:41
+  --> $DIR/subdiagnostic-derive.rs:538:42
    |
-LL | #[multipart_suggestion(parse_add_paren, code = "...", applicability = "machine-applicable")]
-   |                                         ^^^^^^^^^^^^
+LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
+   |                                          ^^^^^^^^^^^^
    |
    = help: only `style` and `applicability` are valid nested attributes
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:536:1
+  --> $DIR/subdiagnostic-derive.rs:538:1
    |
-LL | / #[multipart_suggestion(parse_add_paren, code = "...", applicability = "machine-applicable")]
+LL | / #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
 LL | |
 LL | |
 LL | | struct BBa {
@@ -334,19 +334,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:546:5
+  --> $DIR/subdiagnostic-derive.rs:548:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:554:5
+  --> $DIR/subdiagnostic-derive.rs:556:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:563:5
+  --> $DIR/subdiagnostic-derive.rs:565:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -354,9 +354,9 @@ LL |     #[primary_span]
    = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
 
 error: multipart suggestion without any `#[suggestion_part(...)]` fields
-  --> $DIR/subdiagnostic-derive.rs:560:1
+  --> $DIR/subdiagnostic-derive.rs:562:1
    |
-LL | / #[multipart_suggestion(parse_add_paren)]
+LL | / #[multipart_suggestion(no_crate_example)]
 LL | |
 LL | | struct BC {
 LL | |     #[primary_span]
@@ -366,19 +366,19 @@ LL | | }
    | |_^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:571:5
+  --> $DIR/subdiagnostic-derive.rs:573:5
    |
 LL |     #[suggestion_part]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(...)]` attribute without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:574:5
+  --> $DIR/subdiagnostic-derive.rs:576:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_part(foo = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:577:23
+  --> $DIR/subdiagnostic-derive.rs:579:23
    |
 LL |     #[suggestion_part(foo = "bar")]
    |                       ^^^^^^^^^^^
@@ -386,123 +386,123 @@ LL |     #[suggestion_part(foo = "bar")]
    = help: `code` is the only valid nested attribute
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:580:5
+  --> $DIR/subdiagnostic-derive.rs:582:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
-  --> $DIR/subdiagnostic-derive.rs:583:5
+  --> $DIR/subdiagnostic-derive.rs:585:5
    |
 LL |     #[suggestion_part()]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:591:37
+  --> $DIR/subdiagnostic-derive.rs:593:37
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                                     ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:591:23
+  --> $DIR/subdiagnostic-derive.rs:593:23
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                       ^^^^^^^^^^^^
 
 error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
-  --> $DIR/subdiagnostic-derive.rs:620:5
+  --> $DIR/subdiagnostic-derive.rs:622:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: expected exactly one string literal for `code = ...`
-  --> $DIR/subdiagnostic-derive.rs:668:23
+  --> $DIR/subdiagnostic-derive.rs:670:23
    |
 LL |     #[suggestion_part(code("foo"))]
    |                       ^^^^^^^^^^^
 
 error: expected exactly one string literal for `code = ...`
-  --> $DIR/subdiagnostic-derive.rs:677:23
+  --> $DIR/subdiagnostic-derive.rs:679:23
    |
 LL |     #[suggestion_part(code("foo", "bar"))]
    |                       ^^^^^^^^^^^^^^^^^^
 
 error: expected exactly one string literal for `code = ...`
-  --> $DIR/subdiagnostic-derive.rs:686:23
+  --> $DIR/subdiagnostic-derive.rs:688:23
    |
 LL |     #[suggestion_part(code(3))]
    |                       ^^^^^^^
 
 error: expected exactly one string literal for `code = ...`
-  --> $DIR/subdiagnostic-derive.rs:695:23
+  --> $DIR/subdiagnostic-derive.rs:697:23
    |
 LL |     #[suggestion_part(code())]
    |                       ^^^^^^
 
 error: `code = "..."`/`code(...)` must contain only string literals
-  --> $DIR/subdiagnostic-derive.rs:704:23
+  --> $DIR/subdiagnostic-derive.rs:706:23
    |
 LL |     #[suggestion_part(code = 3)]
    |                       ^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:746:60
+  --> $DIR/subdiagnostic-derive.rs:748:61
    |
-LL | #[suggestion(parse_add_paren, code = "", style = "hidden", style = "normal")]
-   |                                                            ^^^^^^^^^^^^^^^^
+LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
+   |                                                             ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:746:42
+  --> $DIR/subdiagnostic-derive.rs:748:43
    |
-LL | #[suggestion(parse_add_paren, code = "", style = "hidden", style = "normal")]
-   |                                          ^^^^^^^^^^^^^^^^
+LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
+   |                                           ^^^^^^^^^^^^^^^^
 
 error: `#[suggestion_hidden(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:755:1
+  --> $DIR/subdiagnostic-derive.rs:757:1
    |
-LL | #[suggestion_hidden(parse_add_paren, code = "")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion_hidden(no_crate_example, code = "")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Use `#[suggestion(..., style = "hidden")]` instead
 
 error: `#[suggestion_hidden(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:763:1
+  --> $DIR/subdiagnostic-derive.rs:765:1
    |
-LL | #[suggestion_hidden(parse_add_paren, code = "", style = "normal")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Use `#[suggestion(..., style = "hidden")]` instead
 
 error: invalid suggestion style
-  --> $DIR/subdiagnostic-derive.rs:771:50
+  --> $DIR/subdiagnostic-derive.rs:773:51
    |
-LL | #[suggestion(parse_add_paren, code = "", style = "foo")]
-   |                                                  ^^^^^
+LL | #[suggestion(no_crate_example, code = "", style = "foo")]
+   |                                                   ^^^^^
    |
    = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
 
 error: `#[suggestion(style = ...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:779:42
+  --> $DIR/subdiagnostic-derive.rs:781:43
    |
-LL | #[suggestion(parse_add_paren, code = "", style = 42)]
-   |                                          ^^^^^^^^^^
+LL | #[suggestion(no_crate_example, code = "", style = 42)]
+   |                                           ^^^^^^^^^^
 
 error: `#[suggestion(style)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:787:42
+  --> $DIR/subdiagnostic-derive.rs:789:43
    |
-LL | #[suggestion(parse_add_paren, code = "", style)]
-   |                                          ^^^^^
+LL | #[suggestion(no_crate_example, code = "", style)]
+   |                                           ^^^^^
    |
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: `#[suggestion(style(...))]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:795:42
+  --> $DIR/subdiagnostic-derive.rs:797:43
    |
-LL | #[suggestion(parse_add_paren, code = "", style("foo"))]
-   |                                          ^^^^^^^^^^^^
+LL | #[suggestion(no_crate_example, code = "", style("foo"))]
+   |                                           ^^^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:806:5
+  --> $DIR/subdiagnostic-derive.rs:808:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -511,9 +511,9 @@ LL |     #[primary_span]
    = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:803:1
+  --> $DIR/subdiagnostic-derive.rs:805:1
    |
-LL | / #[suggestion(parse_add_paren, code = "")]
+LL | / #[suggestion(no_crate_example, code = "")]
 LL | |
 LL | | struct PrimarySpanOnVec {
 LL | |     #[primary_span]
@@ -523,64 +523,64 @@ LL | | }
    | |_^
 
 error: cannot find attribute `foo` in this scope
-  --> $DIR/subdiagnostic-derive.rs:63:3
+  --> $DIR/subdiagnostic-derive.rs:65:3
    |
 LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `foo` in this scope
-  --> $DIR/subdiagnostic-derive.rs:159:3
+  --> $DIR/subdiagnostic-derive.rs:161:3
    |
 LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:173:7
+  --> $DIR/subdiagnostic-derive.rs:175:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:185:7
+  --> $DIR/subdiagnostic-derive.rs:187:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:197:7
+  --> $DIR/subdiagnostic-derive.rs:199:7
    |
 LL |     #[bar = 4]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:209:7
+  --> $DIR/subdiagnostic-derive.rs:211:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:270:7
+  --> $DIR/subdiagnostic-derive.rs:272:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:281:7
+  --> $DIR/subdiagnostic-derive.rs:283:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:292:7
+  --> $DIR/subdiagnostic-derive.rs:294:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
-error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
-  --> $DIR/subdiagnostic-derive.rs:122:9
+error[E0425]: cannot find value `slug` in module `crate::fluent_generated`
+  --> $DIR/subdiagnostic-derive.rs:124:9
    |
 LL | #[label(slug)]
-   |         ^^^^ not found in `rustc_errors::fluent`
+   |         ^^^^ not found in `crate::fluent_generated`
 
 error: aborting due to 81 previous errors