about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl4
-rw-r--r--compiler/rustc_error_messages/src/lib.rs38
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs1
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs460
-rw-r--r--compiler/rustc_macros/src/diagnostics/error.rs37
-rw-r--r--compiler/rustc_macros/src/diagnostics/fluent.rs11
-rw-r--r--compiler/rustc_macros/src/diagnostics/mod.rs10
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs84
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs24
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs30
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs6
-rw-r--r--compiler/rustc_typeck/src/errors.rs70
-rw-r--r--library/core/src/num/nonzero.rs52
-rw-r--r--library/std/src/alloc.rs2
-rw-r--r--library/std/src/sys/itron/abi.rs48
-rw-r--r--library/std/src/sys/itron/wait_flag.rs72
-rw-r--r--library/std/src/sys/solid/mod.rs2
-rw-r--r--library/std/src/sys_common/thread_parker/mod.rs7
-rw-r--r--library/std/src/sys_common/thread_parker/wait_flag.rs102
-rw-r--r--src/bootstrap/bootstrap.py10
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css74
-rw-r--r--src/librustdoc/html/static/css/settings.css21
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css9
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css9
-rw-r--r--src/librustdoc/html/static/css/themes/light.css9
-rw-r--r--src/librustdoc/html/static/js/main.js177
-rw-r--r--src/librustdoc/html/static/js/settings.js40
-rw-r--r--src/librustdoc/html/templates/page.html4
-rw-r--r--src/test/rustdoc-gui/escape-key.goml12
-rw-r--r--src/test/rustdoc-gui/pocket-menu.goml72
-rw-r--r--src/test/rustdoc-gui/shortcuts.goml5
-rw-r--r--src/test/rustdoc/generic_const_exprs.rs24
-rw-r--r--src/test/ui-fulldeps/internal-lints/diagnostics.rs4
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs241
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr287
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs159
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr207
-rw-r--r--src/test/ui/array-slice-vec/array_const_index-0.stderr13
-rw-r--r--src/test/ui/array-slice-vec/array_const_index-1.stderr13
-rw-r--r--src/test/ui/associated-consts/defaults-not-assumed-fail.stderr25
-rw-r--r--src/test/ui/borrowck/issue-81899.stderr13
-rw-r--r--src/test/ui/borrowck/issue-88434-minimal-example.stderr13
-rw-r--r--src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr13
-rw-r--r--src/test/ui/consts/assert-type-intrinsics.stderr42
-rw-r--r--src/test/ui/consts/assoc_const_generic_impl.stderr17
-rw-r--r--src/test/ui/consts/const-err-early.stderr85
-rw-r--r--src/test/ui/consts/const-err-multi.stderr68
-rw-r--r--src/test/ui/consts/const-err.stderr17
-rw-r--r--src/test/ui/consts/const-eval/conditional_array_execution.stderr33
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow-2.stderr17
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow2.stderr150
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow2b.stderr150
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow2c.stderr150
-rw-r--r--src/test/ui/consts/const-eval/const-eval-query-stack.stderr28
-rw-r--r--src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr351
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr76
-rw-r--r--src/test/ui/consts/const-eval/erroneous-const.stderr17
-rw-r--r--src/test/ui/consts/const-eval/erroneous-const2.stderr17
-rw-r--r--src/test/ui/consts/const-eval/format.stderr46
-rw-r--r--src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr17
-rw-r--r--src/test/ui/consts/const-eval/issue-43197.stderr66
-rw-r--r--src/test/ui/consts/const-eval/issue-44578.stderr33
-rw-r--r--src/test/ui/consts/const-eval/issue-50814-2.stderr13
-rw-r--r--src/test/ui/consts/const-eval/issue-50814.stderr13
-rw-r--r--src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr19
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors.noopt.stderr50
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors.opt.stderr51
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr50
-rw-r--r--src/test/ui/consts/const-eval/pub_const_err.stderr17
-rw-r--r--src/test/ui/consts/const-eval/pub_const_err_bin.stderr17
-rw-r--r--src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr13
-rw-r--r--src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr13
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.32bit.stderr55
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.64bit.stderr55
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr63
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr63
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr83
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr83
-rw-r--r--src/test/ui/consts/const-eval/unused-broken-const.stderr13
-rw-r--r--src/test/ui/consts/const-external-macro-const-err.stderr12
-rw-r--r--src/test/ui/consts/const-float-bits-reject-conv.stderr112
-rw-r--r--src/test/ui/consts/const-len-underflow-separate-spans.stderr13
-rw-r--r--src/test/ui/consts/const-prop-read-static-in-const.stderr13
-rw-r--r--src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr26
-rw-r--r--src/test/ui/consts/const-slice-oob.stderr13
-rw-r--r--src/test/ui/consts/const_limit/const_eval_limit_reached.stderr18
-rw-r--r--src/test/ui/consts/invalid-union.32bit.stderr11
-rw-r--r--src/test/ui/consts/invalid-union.64bit.stderr11
-rw-r--r--src/test/ui/consts/issue-56164.stderr11
-rw-r--r--src/test/ui/consts/issue-66693.stderr11
-rw-r--r--src/test/ui/consts/issue-miri-1910.stderr25
-rw-r--r--src/test/ui/consts/miri_unleashed/assoc_const.stderr25
-rw-r--r--src/test/ui/consts/miri_unleashed/assoc_const_2.stderr17
-rw-r--r--src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr55
-rw-r--r--src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr42
-rw-r--r--src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr42
-rw-r--r--src/test/ui/consts/ptr_comparisons.stderr26
-rw-r--r--src/test/ui/consts/recursive.stderr19
-rw-r--r--src/test/ui/consts/uninhabited-const-issue-61744.stderr144
-rw-r--r--src/test/ui/generic-associated-types/issue-91883.rs42
-rw-r--r--src/test/ui/generic-associated-types/issue-91883.stderr26
-rw-r--r--src/test/ui/limits/issue-55878.stderr12
-rw-r--r--src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr13
-rw-r--r--src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr13
-rw-r--r--src/test/ui/lint/force-warn/deny-by-default-lint.stderr13
-rw-r--r--src/test/ui/mir/issue-92893.rs3
-rw-r--r--src/test/ui/mir/issue-92893.stderr8
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.rs2
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr20
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs88
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr442
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs1
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr26
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/feature-gate.rs3
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr18
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs17
-rw-r--r--src/test/ui/traits/issue-87558.rs9
-rw-r--r--src/test/ui/traits/issue-87558.stderr24
119 files changed, 4911 insertions, 1084 deletions
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index c75d83bd0a0..aa355150b4f 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -36,7 +36,7 @@ pub fn expand_cfg(
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "builtin-macros-requires-cfg-pattern")]
+#[error(builtin_macros::requires_cfg_pattern)]
 struct RequiresCfgPattern {
     #[primary_span]
     #[label]
@@ -44,7 +44,7 @@ struct RequiresCfgPattern {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "builtin-macros-expected-one-cfg-pattern")]
+#[error(builtin_macros::expected_one_cfg_pattern)]
 struct OneCfgPattern {
     #[primary_span]
     span: Span,
diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
index 1d3e33c8185..4a42d52f710 100644
--- a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
@@ -1,5 +1,5 @@
-builtin-macros-requires-cfg-pattern =
+builtin_macros-requires-cfg-pattern =
     macro requires a cfg-pattern as an argument
     .label = cfg-pattern required
 
-builtin-macros-expected-one-cfg-pattern = expected 1 cfg-pattern
+builtin_macros-expected-one-cfg-pattern = expected 1 cfg-pattern
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 7211c054326..673e160cc1e 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -258,18 +258,6 @@ pub enum SubdiagnosticMessage {
     FluentAttr(FluentId),
 }
 
-impl SubdiagnosticMessage {
-    /// Create a `SubdiagnosticMessage` for the provided Fluent attribute.
-    pub fn attr(id: impl Into<FluentId>) -> Self {
-        SubdiagnosticMessage::FluentAttr(id.into())
-    }
-
-    /// Create a `SubdiagnosticMessage` for the provided Fluent identifier.
-    pub fn message(id: impl Into<FluentId>) -> Self {
-        SubdiagnosticMessage::FluentIdentifier(id.into())
-    }
-}
-
 /// `From` impl that enables existing diagnostic calls to functions which now take
 /// `impl Into<SubdiagnosticMessage>` to continue to work as before.
 impl<S: Into<String>> From<S> for SubdiagnosticMessage {
@@ -332,11 +320,6 @@ impl DiagnosticMessage {
             _ => panic!("expected non-translatable diagnostic message"),
         }
     }
-
-    /// Create a `DiagnosticMessage` for the provided Fluent identifier.
-    pub fn new(id: impl Into<FluentId>) -> Self {
-        DiagnosticMessage::FluentIdentifier(id.into(), None)
-    }
 }
 
 /// `From` impl that enables existing diagnostic calls to functions which now take
@@ -347,6 +330,27 @@ impl<S: Into<String>> From<S> for DiagnosticMessage {
     }
 }
 
+/// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but
+/// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagnosticMessage` and the
+/// subdiagnostic derive refers to typed identifiers that are `DiagnosticMessage`s, so need to be
+/// able to convert between these, as much as they'll be converted back into `DiagnosticMessage`
+/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive.
+impl Into<SubdiagnosticMessage> for DiagnosticMessage {
+    fn into(self) -> SubdiagnosticMessage {
+        match self {
+            DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
+            DiagnosticMessage::FluentIdentifier(id, None) => {
+                SubdiagnosticMessage::FluentIdentifier(id)
+            }
+            // There isn't really a sensible behaviour for this because it loses information but
+            // this is the most sensible of the behaviours.
+            DiagnosticMessage::FluentIdentifier(_, Some(attr)) => {
+                SubdiagnosticMessage::FluentAttr(attr)
+            }
+        }
+    }
+}
+
 /// A span together with some additional data.
 #[derive(Clone, Debug)]
 pub struct SpanLabel {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index b1bfd612b90..d52455e2576 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -289,6 +289,7 @@ declare_lint! {
     "constant evaluation encountered erroneous expression",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #71800 <https://github.com/rust-lang/rust/issues/71800>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
     report_in_external_macro
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 95ee0d4a060..d0c86527189 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -12,7 +12,9 @@ use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote};
 use std::collections::HashMap;
 use std::str::FromStr;
-use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, Type};
+use syn::{
+    parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type,
+};
 use synstructure::{BindingInfo, Structure};
 
 /// The central struct for constructing the `into_diagnostic` method from an annotated struct.
@@ -118,23 +120,23 @@ impl<'a> SessionDiagnosticDerive<'a> {
                         return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
                     (Some((kind, _)), None) => {
-                        span_err(span, "`slug` not specified")
-                            .help(&format!("use the `#[{}(slug = \"...\")]` attribute to set this diagnostic's slug", kind.descr()))
+                        span_err(span, "diagnostic slug not specified")
+                            .help(&format!(
+                                "specify the slug as the first argument to the attribute, such as \
+                                 `#[{}(typeck::example_error)]`",
+                                kind.descr()
+                            ))
                             .emit();
                         return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
                     (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => {
                         quote! {
-                            let mut #diag = #sess.struct_err(
-                                rustc_errors::DiagnosticMessage::new(#slug),
-                            );
+                            let mut #diag = #sess.struct_err(rustc_errors::fluent::#slug);
                         }
                     }
                     (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => {
                         quote! {
-                            let mut #diag = #sess.struct_warn(
-                                rustc_errors::DiagnosticMessage::new(#slug),
-                            );
+                            let mut #diag = #sess.struct_warn(rustc_errors::fluent::#slug);
                         }
                     }
                 };
@@ -226,7 +228,7 @@ struct SessionDiagnosticDeriveBuilder {
     kind: Option<(SessionDiagnosticKind, proc_macro::Span)>,
     /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
     /// has the actual diagnostic message.
-    slug: Option<(String, proc_macro::Span)>,
+    slug: Option<(Path, proc_macro::Span)>,
     /// Error codes are a optional part of the struct attribute - this is only set to detect
     /// multiple specifications.
     code: Option<(String, proc_macro::Span)>,
@@ -240,50 +242,79 @@ impl HasFieldMap for SessionDiagnosticDeriveBuilder {
 
 impl SessionDiagnosticDeriveBuilder {
     /// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct
-    /// attributes like `#[error(..)#`, such as the diagnostic kind and slug. Generates
+    /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates
     /// diagnostic builder calls for setting error code and creating note/help messages.
     fn generate_structure_code(
         &mut self,
         attr: &Attribute,
     ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        let diag = &self.diag;
         let span = attr.span().unwrap();
 
         let name = attr.path.segments.last().unwrap().ident.to_string();
         let name = name.as_str();
         let meta = attr.parse_meta()?;
 
-        if matches!(name, "help" | "note") && matches!(meta, Meta::Path(_) | Meta::NameValue(_)) {
-            let diag = &self.diag;
-            let id = match meta {
-                Meta::Path(..) => quote! { #name },
-                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
-                    quote! { #s }
-                }
-                _ => unreachable!(),
-            };
-            let fn_name = proc_macro2::Ident::new(name, attr.span());
-
-            return Ok(quote! {
-                #diag.#fn_name(rustc_errors::SubdiagnosticMessage::attr(#id));
-            });
-        }
+        let is_help_or_note = matches!(name, "help" | "note");
 
         let nested = match meta {
+            // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or
+            // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
             Meta::List(MetaList { ref nested, .. }) => nested,
+            // Subdiagnostics without spans can be applied to the type too, and these are just
+            // paths: `#[help]` and `#[note]`
+            Meta::Path(_) if is_help_or_note => {
+                let fn_name = proc_macro2::Ident::new(name, attr.span());
+                return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); });
+            }
             _ => throw_invalid_attr!(attr, &meta),
         };
 
-        let kind = match name {
-            "error" => SessionDiagnosticKind::Error,
-            "warning" => SessionDiagnosticKind::Warn,
+        // Check the kind before doing any further processing so that there aren't misleading
+        // "no kind specified" errors if there are failures later.
+        match name {
+            "error" => self.kind.set_once((SessionDiagnosticKind::Error, span)),
+            "warning" => self.kind.set_once((SessionDiagnosticKind::Warn, span)),
+            "help" | "note" => (),
             _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help("only `error` and `warning` are valid attributes")
+                diag.help("only `error`, `warning`, `help` and `note` are valid attributes")
             }),
-        };
-        self.kind.set_once((kind, span));
+        }
+
+        // First nested element should always be the path, e.g. `#[error(typeck::invalid)]` or
+        // `#[help(typeck::another_help)]`.
+        let mut nested_iter = nested.into_iter();
+        if let Some(nested_attr) = nested_iter.next() {
+            // Report an error if there are any other list items after the path.
+            if is_help_or_note && nested_iter.next().is_some() {
+                throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                    diag.help("`help` and `note` struct attributes can only have one argument")
+                });
+            }
 
+            match nested_attr {
+                NestedMeta::Meta(Meta::Path(path)) if is_help_or_note => {
+                    let fn_name = proc_macro2::Ident::new(name, attr.span());
+                    return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
+                }
+                NestedMeta::Meta(Meta::Path(path)) => {
+                    self.slug.set_once((path.clone(), span));
+                }
+                NestedMeta::Meta(meta @ Meta::NameValue(_))
+                    if !is_help_or_note
+                        && meta.path().segments.last().unwrap().ident.to_string() == "code" =>
+                {
+                    // don't error for valid follow-up attributes
+                }
+                nested_attr => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                    diag.help("first argument of the attribute should be the diagnostic slug")
+                }),
+            };
+        }
+
+        // Remaining attributes are optional, only `code = ".."` at the moment.
         let mut tokens = Vec::new();
-        for nested_attr in nested {
+        for nested_attr in nested_iter {
             let meta = match nested_attr {
                 syn::NestedMeta::Meta(meta) => meta,
                 _ => throw_invalid_nested_attr!(attr, &nested_attr),
@@ -291,28 +322,24 @@ impl SessionDiagnosticDeriveBuilder {
 
             let path = meta.path();
             let nested_name = path.segments.last().unwrap().ident.to_string();
-            match &meta {
-                // Struct attributes are only allowed to be applied once, and the diagnostic
-                // changes will be set in the initialisation code.
-                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
-                    let span = s.span().unwrap();
-                    match nested_name.as_str() {
-                        "slug" => {
-                            self.slug.set_once((s.value(), span));
-                        }
-                        "code" => {
-                            self.code.set_once((s.value(), span));
-                            let (diag, code) = (&self.diag, &self.code.as_ref().map(|(v, _)| v));
-                            tokens.push(quote! {
-                                #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
-                            });
-                        }
-                        _ => invalid_nested_attr(attr, &nested_attr)
-                            .help("only `slug` and `code` are valid nested attributes")
-                            .emit(),
+            // Struct attributes are only allowed to be applied once, and the diagnostic
+            // changes will be set in the initialisation code.
+            if let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) = &meta {
+                let span = s.span().unwrap();
+                match nested_name.as_str() {
+                    "code" => {
+                        self.code.set_once((s.value(), span));
+                        let code = &self.code.as_ref().map(|(v, _)| v);
+                        tokens.push(quote! {
+                            #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
+                        });
                     }
+                    _ => invalid_nested_attr(attr, &nested_attr)
+                        .help("only `code` is a valid nested attributes following the slug")
+                        .emit(),
                 }
-                _ => invalid_nested_attr(attr, &nested_attr).emit(),
+            } else {
+                invalid_nested_attr(attr, &nested_attr).emit()
             }
         }
 
@@ -382,142 +409,215 @@ impl SessionDiagnosticDeriveBuilder {
         info: FieldInfo<'_>,
         binding: TokenStream,
     ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        let meta = attr.parse_meta()?;
+        match meta {
+            Meta::Path(_) => self.generate_inner_field_code_path(attr, info, binding),
+            Meta::List(MetaList { .. }) => self.generate_inner_field_code_list(attr, info, binding),
+            _ => throw_invalid_attr!(attr, &meta),
+        }
+    }
+
+    fn generate_inner_field_code_path(
+        &mut self,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+        binding: TokenStream,
+    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        assert!(matches!(attr.parse_meta()?, Meta::Path(_)));
         let diag = &self.diag;
 
+        let meta = attr.parse_meta()?;
+
         let ident = &attr.path.segments.last().unwrap().ident;
         let name = ident.to_string();
         let name = name.as_str();
+        match name {
+            "skip_arg" => {
+                // Don't need to do anything - by virtue of the attribute existing, the
+                // `set_arg` call will not be generated.
+                Ok(quote! {})
+            }
+            "primary_span" => {
+                report_error_if_not_applied_to_span(attr, &info)?;
+                Ok(quote! {
+                    #diag.set_span(#binding);
+                })
+            }
+            "label" => {
+                report_error_if_not_applied_to_span(attr, &info)?;
+                Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label }))
+            }
+            "note" | "help" => {
+                let path = match name {
+                    "note" => parse_quote! { _subdiag::note },
+                    "help" => parse_quote! { _subdiag::help },
+                    _ => unreachable!(),
+                };
+                if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+                    Ok(self.add_spanned_subdiagnostic(binding, ident, path))
+                } else if type_is_unit(&info.ty) {
+                    Ok(self.add_subdiagnostic(ident, path))
+                } else {
+                    report_type_error(attr, "`Span` or `()`")?;
+                }
+            }
+            "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
+            _ => throw_invalid_attr!(attr, &meta, |diag| {
+                diag.help(
+                    "only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` \
+                     are valid field attributes",
+                )
+            }),
+        }
+    }
 
+    fn generate_inner_field_code_list(
+        &mut self,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+        binding: TokenStream,
+    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
         let meta = attr.parse_meta()?;
-        match meta {
-            Meta::Path(_) => match name {
-                "skip_arg" => {
-                    // Don't need to do anything - by virtue of the attribute existing, the
-                    // `set_arg` call will not be generated.
-                    Ok(quote! {})
-                }
-                "primary_span" => {
-                    report_error_if_not_applied_to_span(attr, &info)?;
-                    Ok(quote! {
-                        #diag.set_span(#binding);
-                    })
-                }
-                "label" => {
-                    report_error_if_not_applied_to_span(attr, &info)?;
-                    Ok(self.add_spanned_subdiagnostic(binding, ident, name))
-                }
-                "note" | "help" => {
-                    if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
-                        Ok(self.add_spanned_subdiagnostic(binding, ident, name))
-                    } else if type_is_unit(&info.ty) {
-                        Ok(self.add_subdiagnostic(ident, name))
-                    } else {
-                        report_type_error(attr, "`Span` or `()`")?;
-                    }
-                }
-                "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
-                _ => throw_invalid_attr!(attr, &meta, |diag| {
-                    diag
-                        .help("only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes")
-                }),
-            },
-            Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(ref s), .. }) => match name {
-                "label" => {
-                    report_error_if_not_applied_to_span(attr, &info)?;
-                    Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value()))
-                }
-                "note" | "help" => {
-                    if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
-                        Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value()))
-                    } else if type_is_unit(&info.ty) {
-                        Ok(self.add_subdiagnostic(ident, &s.value()))
-                    } else {
-                        report_type_error(attr, "`Span` or `()`")?;
-                    }
-                }
-                _ => throw_invalid_attr!(attr, &meta, |diag| {
-                    diag.help("only `label`, `note` and `help` are valid field attributes")
-                }),
-            },
-            Meta::List(MetaList { ref path, ref nested, .. }) => {
-                let name = path.segments.last().unwrap().ident.to_string();
-                let name = name.as_ref();
-
-                match name {
-                    "suggestion" | "suggestion_short" | "suggestion_hidden"
-                    | "suggestion_verbose" => (),
-                    _ => throw_invalid_attr!(attr, &meta, |diag| {
-                        diag
-                            .help("only `suggestion{,_short,_hidden,_verbose}` are valid field attributes")
-                    }),
-                };
+        let Meta::List(MetaList { ref path, ref nested, .. }) = meta  else { unreachable!() };
 
-                let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
+        let ident = &attr.path.segments.last().unwrap().ident;
+        let name = path.segments.last().unwrap().ident.to_string();
+        let name = name.as_ref();
+        match name {
+            "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => {
+                return self.generate_inner_field_code_suggestion(attr, info);
+            }
+            "label" | "help" | "note" => (),
+            _ => throw_invalid_attr!(attr, &meta, |diag| {
+                diag.help(
+                    "only `label`, `note`, `help` or `suggestion{,_short,_hidden,_verbose}` are \
+                     valid field attributes",
+                )
+            }),
+        }
 
-                let mut msg = None;
-                let mut code = None;
+        // For `#[label(..)]`, `#[note(..)]` and `#[help(..)]`, the first nested element must be a
+        // path, e.g. `#[label(typeck::label)]`.
+        let mut nested_iter = nested.into_iter();
+        let msg = match nested_iter.next() {
+            Some(NestedMeta::Meta(Meta::Path(path))) => path.clone(),
+            Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr),
+            None => throw_invalid_attr!(attr, &meta),
+        };
 
-                for nested_attr in nested {
-                    let meta = match nested_attr {
-                        syn::NestedMeta::Meta(ref meta) => meta,
-                        syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr),
-                    };
+        // None of these attributes should have anything following the slug.
+        if nested_iter.next().is_some() {
+            throw_invalid_attr!(attr, &meta);
+        }
 
-                    let nested_name = meta.path().segments.last().unwrap().ident.to_string();
-                    let nested_name = nested_name.as_str();
-                    match meta {
-                        Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
-                            let span = meta.span().unwrap();
-                            match nested_name {
-                                "message" => {
-                                    msg = Some(s.value());
-                                }
-                                "code" => {
-                                    let formatted_str = self.build_format(&s.value(), s.span());
-                                    code = Some(formatted_str);
+        match name {
+            "label" => {
+                report_error_if_not_applied_to_span(attr, &info)?;
+                Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
+            }
+            "note" | "help" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => {
+                Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
+            }
+            "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)),
+            "note" | "help" => {
+                report_type_error(attr, "`Span` or `()`")?;
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    fn generate_inner_field_code_suggestion(
+        &mut self,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+        let diag = &self.diag;
+
+        let mut meta = attr.parse_meta()?;
+        let Meta::List(MetaList { ref path, ref mut nested, .. }) = meta  else { unreachable!() };
+
+        let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
+
+        let mut msg = None;
+        let mut code = None;
+
+        let mut nested_iter = nested.into_iter().peekable();
+        if let Some(nested_attr) = nested_iter.peek() {
+            if let NestedMeta::Meta(Meta::Path(path)) = nested_attr {
+                msg = Some(path.clone());
+            }
+        };
+        // Move the iterator forward if a path was found (don't otherwise so that
+        // code/applicability can be found or an error emitted).
+        if msg.is_some() {
+            let _ = nested_iter.next();
+        }
+
+        for nested_attr in nested_iter {
+            let meta = match nested_attr {
+                syn::NestedMeta::Meta(ref meta) => meta,
+                syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr),
+            };
+
+            let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+            let nested_name = nested_name.as_str();
+            match meta {
+                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
+                    let span = meta.span().unwrap();
+                    match nested_name {
+                        "code" => {
+                            let formatted_str = self.build_format(&s.value(), s.span());
+                            code = Some(formatted_str);
+                        }
+                        "applicability" => {
+                            applicability = match applicability {
+                                Some(v) => {
+                                    span_err(
+                                        span,
+                                        "applicability cannot be set in both the field and \
+                                         attribute",
+                                    )
+                                    .emit();
+                                    Some(v)
                                 }
-                                "applicability" => {
-                                    applicability = match applicability {
-                                        Some(v) => {
-                                            span_err(
-                                                span,
-                                                "applicability cannot be set in both the field and attribute"
-                                            ).emit();
-                                            Some(v)
-                                        }
-                                        None => match Applicability::from_str(&s.value()) {
-                                            Ok(v) => Some(quote! { #v }),
-                                            Err(()) => {
-                                                span_err(span, "invalid applicability").emit();
-                                                None
-                                            }
-                                        },
+                                None => match Applicability::from_str(&s.value()) {
+                                    Ok(v) => Some(quote! { #v }),
+                                    Err(()) => {
+                                        span_err(span, "invalid applicability").emit();
+                                        None
                                     }
-                                }
-                                _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                                    diag.help(
-                                        "only `message`, `code` and `applicability` are valid field attributes",
-                                    )
-                                }),
+                                },
                             }
                         }
-                        _ => throw_invalid_nested_attr!(attr, &nested_attr),
+                        _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                            diag.help(
+                                "only `message`, `code` and `applicability` are valid field \
+                                 attributes",
+                            )
+                        }),
                     }
                 }
+                _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                    if matches!(meta, Meta::Path(_)) {
+                        diag.help("a diagnostic slug must be the first argument to the attribute")
+                    } else {
+                        diag
+                    }
+                }),
+            }
+        }
 
-                let applicability = applicability
-                    .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
+        let applicability =
+            applicability.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
 
-                let method = format_ident!("span_{}", name);
+        let name = path.segments.last().unwrap().ident.to_string();
+        let method = format_ident!("span_{}", name);
 
-                let msg = msg.as_deref().unwrap_or("suggestion");
-                let msg = quote! { rustc_errors::SubdiagnosticMessage::attr(#msg) };
-                let code = code.unwrap_or_else(|| quote! { String::new() });
+        let msg = msg.unwrap_or_else(|| parse_quote! { _subdiag::suggestion });
+        let msg = quote! { rustc_errors::fluent::#msg };
+        let code = code.unwrap_or_else(|| quote! { String::new() });
 
-                Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
-            }
-            _ => throw_invalid_attr!(attr, &meta),
-        }
+        Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
     }
 
     /// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug
@@ -526,24 +626,24 @@ impl SessionDiagnosticDeriveBuilder {
         &self,
         field_binding: TokenStream,
         kind: &Ident,
-        fluent_attr_identifier: &str,
+        fluent_attr_identifier: Path,
     ) -> TokenStream {
         let diag = &self.diag;
         let fn_name = format_ident!("span_{}", kind);
         quote! {
             #diag.#fn_name(
                 #field_binding,
-                rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier)
+                rustc_errors::fluent::#fluent_attr_identifier
             );
         }
     }
 
     /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug
     /// and `fluent_attr_identifier`.
-    fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream {
+    fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream {
         let diag = &self.diag;
         quote! {
-            #diag.#kind(rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier));
+            #diag.#kind(rustc_errors::fluent::#fluent_attr_identifier);
         }
     }
 
@@ -569,7 +669,8 @@ impl SessionDiagnosticDeriveBuilder {
                         } else {
                             throw_span_err!(
                                 info.span.unwrap(),
-                                "type of field annotated with `#[suggestion(...)]` contains more than one `Span`"
+                                "type of field annotated with `#[suggestion(...)]` contains more \
+                                 than one `Span`"
                             );
                         }
                     } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
@@ -578,7 +679,8 @@ impl SessionDiagnosticDeriveBuilder {
                         } else {
                             throw_span_err!(
                                 info.span.unwrap(),
-                                "type of field annotated with `#[suggestion(...)]` contains more than one Applicability"
+                                "type of field annotated with `#[suggestion(...)]` contains more \
+                                 than one Applicability"
                             );
                         }
                     }
@@ -595,12 +697,18 @@ impl SessionDiagnosticDeriveBuilder {
                 }
 
                 throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
-                    diag.help("`#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`")
+                    diag.help(
+                        "`#[suggestion(...)]` on a tuple field must be applied to fields of type \
+                         `(Span, Applicability)`",
+                    )
                 });
             }
             // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
             _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
-                diag.help("`#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`")
+                diag.help(
+                    "`#[suggestion(...)]` should be applied to fields of type `Span` or \
+                     `(Span, Applicability)`",
+                )
             }),
         }
     }
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
index fd1dc2f3073..d088402abc6 100644
--- a/compiler/rustc_macros/src/diagnostics/error.rs
+++ b/compiler/rustc_macros/src/diagnostics/error.rs
@@ -39,6 +39,19 @@ pub(crate) fn _throw_err(
     SessionDiagnosticDeriveError::ErrorHandled
 }
 
+/// Helper function for printing `syn::Path` - doesn't handle arguments in paths and these are
+/// unlikely to come up much in use of the macro.
+fn path_to_string(path: &syn::Path) -> String {
+    let mut out = String::new();
+    for (i, segment) in path.segments.iter().enumerate() {
+        if i > 0 || path.leading_colon.is_some() {
+            out.push_str("::");
+        }
+        out.push_str(&segment.ident.to_string());
+    }
+    out
+}
+
 /// Returns an error diagnostic on span `span` with msg `msg`.
 pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic {
     Diagnostic::spanned(span, Level::Error, msg)
@@ -61,15 +74,13 @@ pub(crate) use throw_span_err;
 /// Returns an error diagnostic for an invalid attribute.
 pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
     let span = attr.span().unwrap();
-    let name = attr.path.segments.last().unwrap().ident.to_string();
-    let name = name.as_str();
-
+    let path = path_to_string(&attr.path);
     match meta {
-        Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", name)),
+        Meta::Path(_) => span_err(span, &format!("`#[{}]` is not a valid attribute", path)),
         Meta::NameValue(_) => {
-            span_err(span, &format!("`#[{} = ...]` is not a valid attribute", name))
+            span_err(span, &format!("`#[{} = ...]` is not a valid attribute", path))
         }
-        Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", name)),
+        Meta::List(_) => span_err(span, &format!("`#[{}(...)]` is not a valid attribute", path)),
     }
 }
 
@@ -101,18 +112,16 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag
     };
 
     let span = meta.span().unwrap();
-    let nested_name = meta.path().segments.last().unwrap().ident.to_string();
-    let nested_name = nested_name.as_str();
+    let path = path_to_string(meta.path());
     match meta {
-        Meta::NameValue(..) => span_err(
-            span,
-            &format!("`#[{}({} = ...)]` is not a valid attribute", name, nested_name),
-        ),
+        Meta::NameValue(..) => {
+            span_err(span, &format!("`#[{}({} = ...)]` is not a valid attribute", name, path))
+        }
         Meta::Path(..) => {
-            span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, nested_name))
+            span_err(span, &format!("`#[{}({})]` is not a valid attribute", name, path))
         }
         Meta::List(..) => {
-            span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, nested_name))
+            span_err(span, &format!("`#[{}({}(...))]` is not a valid attribute", name, path))
         }
     }
 }
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index 42a9bf477a4..2317186e655 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -254,6 +254,17 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
             ];
 
             #generated
+
+            pub mod _subdiag {
+                pub const note: crate::SubdiagnosticMessage =
+                    crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
+                pub const help: crate::SubdiagnosticMessage =
+                    crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help"));
+                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()
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index 69573d904d4..2eee4bfb5dd 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -22,14 +22,14 @@ use synstructure::Structure;
 /// # extern crate rust_middle;
 /// # use rustc_middle::ty::Ty;
 /// #[derive(SessionDiagnostic)]
-/// #[error(code = "E0505", slug = "borrowck-move-out-of-borrow")]
+/// #[error(borrowck::move_out_of_borrow, code = "E0505")]
 /// pub struct MoveOutOfBorrowError<'tcx> {
 ///     pub name: Ident,
 ///     pub ty: Ty<'tcx>,
 ///     #[primary_span]
 ///     #[label]
 ///     pub span: Span,
-///     #[label = "first-borrow-label"]
+///     #[label(borrowck::first_borrow_label)]
 ///     pub first_borrow_span: Span,
 ///     #[suggestion(code = "{name}.clone()")]
 ///     pub clone_sugg: Option<(Span, Applicability)>
@@ -72,12 +72,12 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
 /// ```ignore (rust)
 /// #[derive(SessionSubdiagnostic)]
 /// pub enum ExpectedIdentifierLabel<'tcx> {
-///     #[label(slug = "parser-expected-identifier")]
+///     #[label(parser::expected_identifier)]
 ///     WithoutFound {
 ///         #[primary_span]
 ///         span: Span,
 ///     }
-///     #[label(slug = "parser-expected-identifier-found")]
+///     #[label(parser::expected_identifier_found)]
 ///     WithFound {
 ///         #[primary_span]
 ///         span: Span,
@@ -86,7 +86,7 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
 /// }
 ///
 /// #[derive(SessionSubdiagnostic)]
-/// #[suggestion_verbose(slug = "parser-raw-identifier")]
+/// #[suggestion_verbose(parser::raw_identifier)]
 /// pub struct RawIdentifierSuggestion<'tcx> {
 ///     #[primary_span]
 ///     span: Span,
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 9aeb484bfd5..eab954a9c1b 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -13,7 +13,7 @@ use quote::{format_ident, quote};
 use std::collections::HashMap;
 use std::fmt;
 use std::str::FromStr;
-use syn::{spanned::Spanned, Meta, MetaList, MetaNameValue};
+use syn::{parse_quote, spanned::Spanned, Meta, MetaList, MetaNameValue, NestedMeta, Path};
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
 /// Which kind of suggestion is being created?
@@ -194,8 +194,8 @@ struct SessionSubdiagnosticDeriveBuilder<'a> {
     kind: Option<(SubdiagnosticKind, proc_macro::Span)>,
 
     /// Slug of the subdiagnostic - corresponds to the Fluent identifier for the message - from the
-    /// `#[kind(slug = "...")]` attribute on the type or variant.
-    slug: Option<(String, proc_macro::Span)>,
+    /// `#[kind(slug)]` attribute on the type or variant.
+    slug: Option<(Path, proc_macro::Span)>,
     /// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]`
     /// attribute on the type or variant.
     code: Option<(TokenStream, proc_macro::Span)>,
@@ -224,9 +224,34 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
             let meta = attr.parse_meta()?;
             let kind = match meta {
                 Meta::List(MetaList { ref nested, .. }) => {
-                    for nested_attr in nested {
+                    let mut nested_iter = nested.into_iter();
+                    if let Some(nested_attr) = nested_iter.next() {
+                        match nested_attr {
+                            NestedMeta::Meta(Meta::Path(path)) => {
+                                self.slug.set_once((path.clone(), span));
+                            }
+                            NestedMeta::Meta(meta @ Meta::NameValue(_))
+                                if matches!(
+                                    meta.path().segments.last().unwrap().ident.to_string().as_str(),
+                                    "code" | "applicability"
+                                ) =>
+                            {
+                                // don't error for valid follow-up attributes
+                            }
+                            nested_attr => {
+                                throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                                    diag.help(
+                                        "first argument of the attribute should be the diagnostic \
+                                         slug",
+                                    )
+                                })
+                            }
+                        };
+                    }
+
+                    for nested_attr in nested_iter {
                         let meta = match nested_attr {
-                            syn::NestedMeta::Meta(ref meta) => meta,
+                            NestedMeta::Meta(ref meta) => meta,
                             _ => throw_invalid_nested_attr!(attr, &nested_attr),
                         };
 
@@ -241,7 +266,6 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
                                         let formatted_str = self.build_format(&s.value(), s.span());
                                         self.code.set_once((formatted_str, span));
                                     }
-                                    "slug" => self.slug.set_once((s.value(), span)),
                                     "applicability" => {
                                         let value = match Applicability::from_str(&s.value()) {
                                             Ok(v) => v,
@@ -253,11 +277,23 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
                                         self.applicability.set_once((quote! { #value }, span));
                                     }
                                     _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                                        diag.help("only `code`, `slug` and `applicability` are valid nested attributes")
+                                        diag.help(
+                                            "only `code` and `applicability` are valid nested \
+                                             attributes",
+                                        )
                                     }),
                                 }
                             }
-                            _ => throw_invalid_nested_attr!(attr, &nested_attr),
+                            _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                                if matches!(meta, Meta::Path(_)) {
+                                    diag.help(
+                                        "a diagnostic slug must be the first argument to the \
+                                         attribute",
+                                    )
+                                } else {
+                                    diag
+                                }
+                            }),
                         }
                     }
 
@@ -281,10 +317,27 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
                 );
             }
 
+            if matches!(
+                kind,
+                SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note
+            ) && self.applicability.is_some()
+            {
+                throw_span_err!(
+                    span,
+                    &format!(
+                        "`applicability` is not a valid nested attribute of a `{}` attribute",
+                        name
+                    )
+                );
+            }
+
             if self.slug.is_none() {
                 throw_span_err!(
                     span,
-                    &format!("`slug` must be set in a `#[{}(...)]` attribute", name)
+                    &format!(
+                        "diagnostic slug must be first argument of a `#[{}(...)]` attribute",
+                        name
+                    )
                 );
             }
 
@@ -335,7 +388,10 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
                         return Ok(quote! {});
                     }
                     _ => throw_invalid_attr!(attr, &meta, |diag| {
-                        diag.help("only `primary_span`, `applicability` and `skip_arg` are valid field attributes")
+                        diag.help(
+                            "only `primary_span`, `applicability` and `skip_arg` are valid field \
+                             attributes",
+                        )
                     }),
                 },
                 _ => throw_invalid_attr!(attr, &meta),
@@ -375,7 +431,11 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
         }
 
         // Missing slug errors will already have been reported.
-        let slug = self.slug.as_ref().map(|(slug, _)| &**slug).unwrap_or("missing-slug");
+        let slug = self
+            .slug
+            .as_ref()
+            .map(|(slug, _)| slug.clone())
+            .unwrap_or_else(|| parse_quote! { you::need::to::specify::a::slug });
         let code = match self.code.as_ref() {
             Some((code, _)) => Some(quote! { #code }),
             None if is_suggestion => {
@@ -397,7 +457,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
 
         let diag = &self.diag;
         let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
-        let message = quote! { rustc_errors::SubdiagnosticMessage::message(#slug) };
+        let message = quote! { rustc_errors::fluent::#slug };
         let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) {
             if let Some(span) = span_field {
                 quote! { #diag.#name(#span, #message, #code, #applicability); }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index ba325d70422..58d5d43cfbf 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -244,7 +244,7 @@ impl MultiSugg {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-maybe-report-ambiguous-plus")]
+#[error(parser::maybe_report_ambiguous_plus)]
 struct AmbiguousPlus {
     pub sum_ty: String,
     #[primary_span]
@@ -253,7 +253,7 @@ struct AmbiguousPlus {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0178", slug = "parser-maybe-recover-from-bad-type-plus")]
+#[error(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
 struct BadTypePlus {
     pub ty: String,
     #[primary_span]
@@ -265,7 +265,7 @@ struct BadTypePlus {
 #[derive(SessionSubdiagnostic)]
 pub enum BadTypePlusSub {
     #[suggestion(
-        slug = "parser-add-paren",
+        parser::add_paren,
         code = "{sum_with_parens}",
         applicability = "machine-applicable"
     )]
@@ -274,12 +274,12 @@ pub enum BadTypePlusSub {
         #[primary_span]
         span: Span,
     },
-    #[label(slug = "parser-forgot-paren")]
+    #[label(parser::forgot_paren)]
     ForgotParen {
         #[primary_span]
         span: Span,
     },
-    #[label(slug = "parser-expect-path")]
+    #[label(parser::expect_path)]
     ExpectPath {
         #[primary_span]
         span: Span,
@@ -287,7 +287,7 @@ pub enum BadTypePlusSub {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")]
+#[error(parser::maybe_recover_from_bad_qpath_stage_2)]
 struct BadQPathStage2 {
     #[primary_span]
     #[suggestion(applicability = "maybe-incorrect")]
@@ -296,7 +296,7 @@ struct BadQPathStage2 {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-incorrect-semicolon")]
+#[error(parser::incorrect_semicolon)]
 struct IncorrectSemicolon<'a> {
     #[primary_span]
     #[suggestion_short(applicability = "machine-applicable")]
@@ -307,26 +307,26 @@ struct IncorrectSemicolon<'a> {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-incorrect-use-of-await")]
+#[error(parser::incorrect_use_of_await)]
 struct IncorrectUseOfAwait {
     #[primary_span]
-    #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")]
+    #[suggestion(parser::parentheses_suggestion, applicability = "machine-applicable")]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-incorrect-use-of-await")]
+#[error(parser::incorrect_use_of_await)]
 struct IncorrectAwait {
     #[primary_span]
     span: Span,
-    #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")]
+    #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")]
     sugg_span: (Span, Applicability),
     expr: String,
     question_mark: &'static str,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-in-in-typo")]
+#[error(parser::in_in_typo)]
 struct InInTypo {
     #[primary_span]
     span: Span,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 81bab0e3513..2c43563b104 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -7,6 +7,7 @@ use super::{
 };
 use crate::maybe_recover_from_interpolated_ty_qpath;
 
+use core::mem;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::Spacing;
@@ -26,7 +27,6 @@ use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
-use std::mem;
 
 /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
 /// dropped into the token stream, which happens while parsing the result of
@@ -2343,7 +2343,9 @@ impl<'a> Parser<'a> {
 
     /// Parses the condition of a `if` or `while` expression.
     fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
-        let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
+        let cond = self.with_let_management(true, |local_self| {
+            local_self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)
+        })?;
 
         if let ExprKind::Let(..) = cond.kind {
             // Remove the last feature gating of a `let` expression since it's stable.
@@ -2356,6 +2358,13 @@ impl<'a> Parser<'a> {
     /// Parses a `let $pat = $expr` pseudo-expression.
     /// The `let` token has already been eaten.
     fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        if !self.let_expr_allowed {
+            self.struct_span_err(
+                self.prev_token.span,
+                "expected expression, found `let` statement",
+            )
+            .emit();
+        }
         let lo = self.prev_token.span;
         let pat = self.parse_pat_allow_top_alt(
             None,
@@ -2672,6 +2681,8 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
+        // Used to check the `let_chains` and `if_let_guard` features mostly by scaning
+        // `&&` tokens.
         fn check_let_expr(expr: &Expr) -> (bool, bool) {
             match expr.kind {
                 ExprKind::Binary(_, ref lhs, ref rhs) => {
@@ -2694,7 +2705,7 @@ impl<'a> Parser<'a> {
             )?;
             let guard = if this.eat_keyword(kw::If) {
                 let if_span = this.prev_token.span;
-                let cond = this.parse_expr()?;
+                let cond = this.with_let_management(true, |local_this| local_this.parse_expr())?;
                 let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
                 if has_let_expr {
                     if does_not_have_bin_op {
@@ -3256,4 +3267,17 @@ impl<'a> Parser<'a> {
             Ok((res, trailing))
         })
     }
+
+    // Calls `f` with the internal `let_expr_allowed` set to `let_expr_allowed` and then
+    // sets the internal `let_expr_allowed` back to its original value.
+    fn with_let_management<T>(
+        &mut self,
+        let_expr_allowed: bool,
+        f: impl FnOnce(&mut Self) -> T,
+    ) -> T {
+        let last_let_expr_allowed = mem::replace(&mut self.let_expr_allowed, let_expr_allowed);
+        let rslt = f(self);
+        self.let_expr_allowed = last_let_expr_allowed;
+        rslt
+    }
 }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 6d6667717f0..acdf121522a 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -147,12 +147,15 @@ pub struct Parser<'a> {
     /// This allows us to recover when the user forget to add braces around
     /// multiple statements in the closure body.
     pub current_closure: Option<ClosureSpans>,
+    /// Used to track where `let`s are allowed. For example, `if true && let 1 = 1` is valid
+    /// but `[1, 2, 3][let _ = ()]` is not.
+    let_expr_allowed: bool,
 }
 
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 328);
+rustc_data_structures::static_assert_size!(Parser<'_>, 336);
 
 /// Stores span information about a closure.
 #[derive(Clone)]
@@ -455,6 +458,7 @@ impl<'a> Parser<'a> {
                 inner_attr_ranges: Default::default(),
             },
             current_closure: None,
+            let_expr_allowed: false,
         };
 
         // Make parser point to the first token.
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 67a3d4a4d02..4cdec615d82 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -6,18 +6,18 @@ use rustc_session::{parse::ParseSess, SessionDiagnostic};
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0062", slug = "typeck-field-multiply-specified-in-initializer")]
+#[error(typeck::field_multiply_specified_in_initializer, code = "E0062")]
 pub struct FieldMultiplySpecifiedInInitializer {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label = "previous-use-label"]
+    #[label(typeck::previous_use_label)]
     pub prev_span: Span,
     pub ident: Ident,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0092", slug = "typeck-unrecognized-atomic-operation")]
+#[error(typeck::unrecognized_atomic_operation, code = "E0092")]
 pub struct UnrecognizedAtomicOperation<'a> {
     #[primary_span]
     #[label]
@@ -26,7 +26,7 @@ pub struct UnrecognizedAtomicOperation<'a> {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0094", slug = "typeck-wrong-number-of-generic-arguments-to-intrinsic")]
+#[error(typeck::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
 pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
     #[primary_span]
     #[label]
@@ -37,7 +37,7 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0093", slug = "typeck-unrecognized-intrinsic-function")]
+#[error(typeck::unrecognized_intrinsic_function, code = "E0093")]
 pub struct UnrecognizedIntrinsicFunction {
     #[primary_span]
     #[label]
@@ -46,19 +46,19 @@ pub struct UnrecognizedIntrinsicFunction {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")]
+#[error(typeck::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
 pub struct LifetimesOrBoundsMismatchOnTrait {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label = "generics-label"]
+    #[label(typeck::generics_label)]
     pub generics_span: Option<Span>,
     pub item_kind: &'static str,
     pub ident: Ident,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0120", slug = "typeck-drop-impl-on-wrong-item")]
+#[error(typeck::drop_impl_on_wrong_item, code = "E0120")]
 pub struct DropImplOnWrongItem {
     #[primary_span]
     #[label]
@@ -66,18 +66,18 @@ pub struct DropImplOnWrongItem {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0124", slug = "typeck-field-already-declared")]
+#[error(typeck::field_already_declared, code = "E0124")]
 pub struct FieldAlreadyDeclared {
     pub field_name: Ident,
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label = "previous-decl-label"]
+    #[label(typeck::previous_decl_label)]
     pub prev_span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0184", slug = "typeck-copy-impl-on-type-with-dtor")]
+#[error(typeck::copy_impl_on_type_with_dtor, code = "E0184")]
 pub struct CopyImplOnTypeWithDtor {
     #[primary_span]
     #[label]
@@ -85,14 +85,14 @@ pub struct CopyImplOnTypeWithDtor {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0203", slug = "typeck-multiple-relaxed-default-bounds")]
+#[error(typeck::multiple_relaxed_default_bounds, code = "E0203")]
 pub struct MultipleRelaxedDefaultBounds {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0206", slug = "typeck-copy-impl-on-non-adt")]
+#[error(typeck::copy_impl_on_non_adt, code = "E0206")]
 pub struct CopyImplOnNonAdt {
     #[primary_span]
     #[label]
@@ -100,23 +100,23 @@ pub struct CopyImplOnNonAdt {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0224", slug = "typeck-trait-object-declared-with-no-traits")]
+#[error(typeck::trait_object_declared_with_no_traits, code = "E0224")]
 pub struct TraitObjectDeclaredWithNoTraits {
     #[primary_span]
     pub span: Span,
-    #[label = "alias-span"]
+    #[label(typeck::alias_span)]
     pub trait_alias_span: Option<Span>,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0227", slug = "typeck-ambiguous-lifetime-bound")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0227")]
 pub struct AmbiguousLifetimeBound {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0229", slug = "typeck-assoc-type-binding-not-allowed")]
+#[error(typeck::assoc_type_binding_not_allowed, code = "E0229")]
 pub struct AssocTypeBindingNotAllowed {
     #[primary_span]
     #[label]
@@ -124,14 +124,14 @@ pub struct AssocTypeBindingNotAllowed {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0436", slug = "typeck-functional-record-update-on-non-struct")]
+#[error(typeck::functional_record_update_on_non_struct, code = "E0436")]
 pub struct FunctionalRecordUpdateOnNonStruct {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")]
+#[error(typeck::typeof_reserved_keyword_used, code = "E0516")]
 pub struct TypeofReservedKeywordUsed<'tcx> {
     pub ty: Ty<'tcx>,
     #[primary_span]
@@ -142,25 +142,25 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0572", slug = "typeck-return-stmt-outside-of-fn-body")]
+#[error(typeck::return_stmt_outside_of_fn_body, code = "E0572")]
 pub struct ReturnStmtOutsideOfFnBody {
     #[primary_span]
     pub span: Span,
-    #[label = "encl-body-label"]
+    #[label(typeck::encl_body_label)]
     pub encl_body_span: Option<Span>,
-    #[label = "encl-fn-label"]
+    #[label(typeck::encl_fn_label)]
     pub encl_fn_span: Option<Span>,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0627", slug = "typeck-yield-expr-outside-of-generator")]
+#[error(typeck::yield_expr_outside_of_generator, code = "E0627")]
 pub struct YieldExprOutsideOfGenerator {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0639", slug = "typeck-struct-expr-non-exhaustive")]
+#[error(typeck::struct_expr_non_exhaustive, code = "E0639")]
 pub struct StructExprNonExhaustive {
     #[primary_span]
     pub span: Span,
@@ -168,26 +168,26 @@ pub struct StructExprNonExhaustive {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0699", slug = "typeck-method-call-on-unknown-type")]
+#[error(typeck::method_call_on_unknown_type, code = "E0699")]
 pub struct MethodCallOnUnknownType {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0719", slug = "typeck-value-of-associated-struct-already-specified")]
+#[error(typeck::value_of_associated_struct_already_specified, code = "E0719")]
 pub struct ValueOfAssociatedStructAlreadySpecified {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label = "previous-bound-label"]
+    #[label(typeck::previous_bound_label)]
     pub prev_span: Span,
     pub item_name: Ident,
     pub def_path: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0745", slug = "typeck-address-of-temporary-taken")]
+#[error(typeck::address_of_temporary_taken, code = "E0745")]
 pub struct AddressOfTemporaryTaken {
     #[primary_span]
     #[label]
@@ -197,7 +197,7 @@ pub struct AddressOfTemporaryTaken {
 #[derive(SessionSubdiagnostic)]
 pub enum AddReturnTypeSuggestion<'tcx> {
     #[suggestion(
-        slug = "typeck-add-return-type-add",
+        typeck::add_return_type_add,
         code = "-> {found} ",
         applicability = "machine-applicable"
     )]
@@ -207,7 +207,7 @@ pub enum AddReturnTypeSuggestion<'tcx> {
         found: Ty<'tcx>,
     },
     #[suggestion(
-        slug = "typeck-add-return-type-missing-here",
+        typeck::add_return_type_missing_here,
         code = "-> _ ",
         applicability = "has-placeholders"
     )]
@@ -219,12 +219,12 @@ pub enum AddReturnTypeSuggestion<'tcx> {
 
 #[derive(SessionSubdiagnostic)]
 pub enum ExpectedReturnTypeLabel<'tcx> {
-    #[label(slug = "typeck-expected-default-return-type")]
+    #[label(typeck::expected_default_return_type)]
     Unit {
         #[primary_span]
         span: Span,
     },
-    #[label(slug = "typeck-expected-return-type")]
+    #[label(typeck::expected_return_type)]
     Other {
         #[primary_span]
         span: Span,
@@ -233,7 +233,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "typeck-unconstrained-opaque-type")]
+#[error(typeck::unconstrained_opaque_type)]
 #[note]
 pub struct UnconstrainedOpaqueType {
     #[primary_span]
@@ -301,7 +301,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0183", slug = "typeck-manual-implementation")]
+#[error(typeck::manual_implementation, code = "E0183")]
 #[help]
 pub struct ManualImplementation {
     #[primary_span]
@@ -311,7 +311,7 @@ pub struct ManualImplementation {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "typeck-substs-on-overridden-impl")]
+#[error(typeck::substs_on_overridden_impl)]
 pub struct SubstsOnOverriddenImpl {
     #[primary_span]
     pub span: Span,
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 70969edd6ea..e570d831cc6 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -316,7 +316,6 @@ macro_rules! nonzero_unsigned_operations {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -331,7 +330,8 @@ macro_rules! nonzero_unsigned_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -351,7 +351,6 @@ macro_rules! nonzero_unsigned_operations {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -366,7 +365,8 @@ macro_rules! nonzero_unsigned_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -415,7 +415,6 @@ macro_rules! nonzero_unsigned_operations {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -432,7 +431,8 @@ macro_rules! nonzero_unsigned_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -521,7 +521,6 @@ macro_rules! nonzero_signed_operations {
                 /// # Example
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -534,7 +533,8 @@ macro_rules! nonzero_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -551,7 +551,6 @@ macro_rules! nonzero_signed_operations {
                 /// # Example
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -566,7 +565,8 @@ macro_rules! nonzero_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -586,7 +586,6 @@ macro_rules! nonzero_signed_operations {
                 /// # Example
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -602,7 +601,8 @@ macro_rules! nonzero_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -621,7 +621,6 @@ macro_rules! nonzero_signed_operations {
                 /// # Example
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -642,7 +641,8 @@ macro_rules! nonzero_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -657,7 +657,6 @@ macro_rules! nonzero_signed_operations {
                 /// # Example
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -677,7 +676,8 @@ macro_rules! nonzero_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -692,7 +692,6 @@ macro_rules! nonzero_signed_operations {
                 /// # Example
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 #[doc = concat!("# use std::num::", stringify!($Uty), ";")]
                 ///
@@ -712,7 +711,8 @@ macro_rules! nonzero_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -746,7 +746,6 @@ macro_rules! nonzero_unsigned_signed_operations {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -761,7 +760,8 @@ macro_rules! nonzero_unsigned_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -782,7 +782,6 @@ macro_rules! nonzero_unsigned_signed_operations {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -797,7 +796,8 @@ macro_rules! nonzero_unsigned_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -855,7 +855,6 @@ macro_rules! nonzero_unsigned_signed_operations {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -870,7 +869,8 @@ macro_rules! nonzero_unsigned_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
@@ -899,7 +899,6 @@ macro_rules! nonzero_unsigned_signed_operations {
                 /// # Examples
                 ///
                 /// ```
-                /// #![feature(nonzero_ops)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
                 /// # fn main() { test().unwrap(); }
@@ -914,7 +913,8 @@ macro_rules! nonzero_unsigned_signed_operations {
                 /// # Some(())
                 /// # }
                 /// ```
-                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[stable(feature = "nonzero_checked_ops", since = "1.64.0")]
+                #[rustc_const_stable(feature = "const_nonzero_checked_ops", since = "1.64.0")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index d554ec59035..a05e0db3af7 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -102,7 +102,7 @@ pub use alloc_crate::alloc::*;
 ///         if !ret.is_null() {
 ///             ALLOCATED.fetch_add(layout.size(), SeqCst);
 ///         }
-///         return ret
+///         ret
 ///     }
 ///
 ///     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
diff --git a/library/std/src/sys/itron/abi.rs b/library/std/src/sys/itron/abi.rs
index f99ee4fa897..5eb14bb7e53 100644
--- a/library/std/src/sys/itron/abi.rs
+++ b/library/std/src/sys/itron/abi.rs
@@ -30,15 +30,32 @@ pub type ER = int_t;
 /// Error code type, `ID` on success
 pub type ER_ID = int_t;
 
+/// Service call operational mode
+pub type MODE = uint_t;
+
+/// OR waiting condition for an eventflag
+pub const TWF_ORW: MODE = 0x01;
+
+/// Object attributes
+pub type ATR = uint_t;
+
+/// FIFO wait order
+pub const TA_FIFO: ATR = 0;
+/// Only one task is allowed to be in the waiting state for the eventflag
+pub const TA_WSGL: ATR = 0;
+/// The eventflag’s bit pattern is cleared when a task is released from the
+/// waiting state for that eventflag.
+pub const TA_CLR: ATR = 0x04;
+
+/// Bit pattern of an eventflag
+pub type FLGPTN = uint_t;
+
 /// Task or interrupt priority
 pub type PRI = int_t;
 
 /// The special value of `PRI` representing the current task's priority.
 pub const TPRI_SELF: PRI = 0;
 
-/// Object attributes
-pub type ATR = uint_t;
-
 /// Use the priority inheritance protocol
 #[cfg(target_os = "solid_asp3")]
 pub const TA_INHERIT: ATR = 0x02;
@@ -92,6 +109,13 @@ pub struct T_CSEM {
 
 #[derive(Clone, Copy)]
 #[repr(C)]
+pub struct T_CFLG {
+    pub flgatr: ATR,
+    pub iflgptn: FLGPTN,
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
 pub struct T_CMTX {
     pub mtxatr: ATR,
     pub ceilpri: PRI,
@@ -139,6 +163,24 @@ extern "C" {
     pub fn sns_dsp() -> bool_t;
     #[link_name = "__asp3_get_tim"]
     pub fn get_tim(p_systim: *mut SYSTIM) -> ER;
+    #[link_name = "__asp3_acre_flg"]
+    pub fn acre_flg(pk_cflg: *const T_CFLG) -> ER_ID;
+    #[link_name = "__asp3_del_flg"]
+    pub fn del_flg(flgid: ID) -> ER;
+    #[link_name = "__asp3_set_flg"]
+    pub fn set_flg(flgid: ID, setptn: FLGPTN) -> ER;
+    #[link_name = "__asp3_clr_flg"]
+    pub fn clr_flg(flgid: ID, clrptn: FLGPTN) -> ER;
+    #[link_name = "__asp3_wai_flg"]
+    pub fn wai_flg(flgid: ID, waiptn: FLGPTN, wfmode: MODE, p_flgptn: *mut FLGPTN) -> ER;
+    #[link_name = "__asp3_twai_flg"]
+    pub fn twai_flg(
+        flgid: ID,
+        waiptn: FLGPTN,
+        wfmode: MODE,
+        p_flgptn: *mut FLGPTN,
+        tmout: TMO,
+    ) -> ER;
     #[link_name = "__asp3_acre_mtx"]
     pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID;
     #[link_name = "__asp3_del_mtx"]
diff --git a/library/std/src/sys/itron/wait_flag.rs b/library/std/src/sys/itron/wait_flag.rs
new file mode 100644
index 00000000000..e432edd2077
--- /dev/null
+++ b/library/std/src/sys/itron/wait_flag.rs
@@ -0,0 +1,72 @@
+use crate::mem::MaybeUninit;
+use crate::time::Duration;
+
+use super::{
+    abi,
+    error::{expect_success, fail},
+    time::with_tmos,
+};
+
+const CLEAR: abi::FLGPTN = 0;
+const RAISED: abi::FLGPTN = 1;
+
+/// A thread parking primitive that is not susceptible to race conditions,
+/// but provides no atomic ordering guarantees and allows only one `raise` per wait.
+pub struct WaitFlag {
+    flag: abi::ID,
+}
+
+impl WaitFlag {
+    /// Creates a new wait flag.
+    pub fn new() -> WaitFlag {
+        let flag = expect_success(
+            unsafe {
+                abi::acre_flg(&abi::T_CFLG {
+                    flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR,
+                    iflgptn: CLEAR,
+                })
+            },
+            &"acre_flg",
+        );
+
+        WaitFlag { flag }
+    }
+
+    /// Wait for the wait flag to be raised.
+    pub fn wait(&self) {
+        let mut token = MaybeUninit::uninit();
+        expect_success(
+            unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) },
+            &"wai_flg",
+        );
+    }
+
+    /// Wait for the wait flag to be raised or the timeout to occur.
+    ///
+    /// Returns whether the flag was raised (`true`) or the operation timed out (`false`).
+    pub fn wait_timeout(&self, dur: Duration) -> bool {
+        let mut token = MaybeUninit::uninit();
+        let res = with_tmos(dur, |tmout| unsafe {
+            abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout)
+        });
+
+        match res {
+            abi::E_OK => true,
+            abi::E_TMOUT => false,
+            error => fail(error, &"twai_flg"),
+        }
+    }
+
+    /// Raise the wait flag.
+    ///
+    /// Calls to this function should be balanced with the number of successful waits.
+    pub fn raise(&self) {
+        expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg");
+    }
+}
+
+impl Drop for WaitFlag {
+    fn drop(&mut self) {
+        expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg");
+    }
+}
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 5ffa381f2e5..2d21e4764fc 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -15,6 +15,7 @@ mod itron {
     pub mod thread;
     pub(super) mod time;
     use super::unsupported;
+    pub mod wait_flag;
 }
 
 pub mod alloc;
@@ -43,6 +44,7 @@ pub mod memchr;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
 pub mod time;
+pub use self::itron::wait_flag;
 
 mod rwlock;
 
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
index 7e8bfb2565e..cbd7832eb7a 100644
--- a/library/std/src/sys_common/thread_parker/mod.rs
+++ b/library/std/src/sys_common/thread_parker/mod.rs
@@ -10,9 +10,10 @@ cfg_if::cfg_if! {
     ))] {
         mod futex;
         pub use futex::Parker;
-    } else if #[cfg(windows)] {
-        pub use crate::sys::thread_parker::Parker;
-    } else if #[cfg(target_family = "unix")] {
+    } else if #[cfg(target_os = "solid_asp3")] {
+        mod wait_flag;
+        pub use wait_flag::Parker;
+    } else if #[cfg(any(windows, target_family = "unix"))] {
         pub use crate::sys::thread_parker::Parker;
     } else {
         mod generic;
diff --git a/library/std/src/sys_common/thread_parker/wait_flag.rs b/library/std/src/sys_common/thread_parker/wait_flag.rs
new file mode 100644
index 00000000000..6561c186655
--- /dev/null
+++ b/library/std/src/sys_common/thread_parker/wait_flag.rs
@@ -0,0 +1,102 @@
+//! A wait-flag-based thread parker.
+//!
+//! Some operating systems provide low-level parking primitives like wait counts,
+//! event flags or semaphores which are not susceptible to race conditions (meaning
+//! the wakeup can occur before the wait operation). To implement the `std` thread
+//! parker on top of these primitives, we only have to ensure that parking is fast
+//! when the thread token is available, the atomic ordering guarantees are maintained
+//! and spurious wakeups are minimized.
+//!
+//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
+//! `PARKED` and `NOTIFIED`:
+//! * `EMPTY` means the token has not been made available, but the thread is not
+//!    currently waiting on it.
+//! * `PARKED` means the token is not available and the thread is parked.
+//! * `NOTIFIED` means the token is available.
+//!
+//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
+//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
+//! execution can continue without calling into the OS. If the state was `EMPTY`,
+//! the token is not available and the thread waits on the primitive (here called
+//! "wait flag").
+//!
+//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
+//! is or will be sleeping on the wait flag, so we raise it.
+
+use crate::pin::Pin;
+use crate::sync::atomic::AtomicI8;
+use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sys::wait_flag::WaitFlag;
+use crate::time::Duration;
+
+const EMPTY: i8 = 0;
+const PARKED: i8 = -1;
+const NOTIFIED: i8 = 1;
+
+pub struct Parker {
+    state: AtomicI8,
+    wait_flag: WaitFlag,
+}
+
+impl Parker {
+    /// Construct a parker for the current thread. The UNIX parker
+    /// implementation requires this to happen in-place.
+    pub unsafe fn new(parker: *mut Parker) {
+        parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park(self: Pin<&Self>) {
+        match self.state.fetch_sub(1, Acquire) {
+            // NOTIFIED => EMPTY
+            NOTIFIED => return,
+            // EMPTY => PARKED
+            EMPTY => (),
+            _ => panic!("inconsistent park state"),
+        }
+
+        // Avoid waking up from spurious wakeups (these are quite likely, see below).
+        loop {
+            self.wait_flag.wait();
+
+            match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
+                Ok(_) => return,
+                Err(PARKED) => (),
+                Err(_) => panic!("inconsistent park state"),
+            }
+        }
+    }
+
+    // This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
+    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
+        match self.state.fetch_sub(1, Acquire) {
+            NOTIFIED => return,
+            EMPTY => (),
+            _ => panic!("inconsistent park state"),
+        }
+
+        self.wait_flag.wait_timeout(dur);
+
+        // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
+        // a race condition when `unpark` is performed between receiving the timeout and
+        // resetting the state, resulting in the eventflag being set unnecessarily. `park`
+        // is protected against this by looping until the token is actually given, but
+        // here we cannot easily tell.
+
+        // Use `swap` to provide acquire ordering.
+        match self.state.swap(EMPTY, Acquire) {
+            NOTIFIED => (),
+            PARKED => (),
+            _ => panic!("inconsistent park state"),
+        }
+    }
+
+    // This implementation doesn't require `Pin`, but other implementations do.
+    pub fn unpark(self: Pin<&Self>) {
+        let state = self.state.swap(NOTIFIED, Release);
+
+        if state == PARKED {
+            self.wait_flag.raise();
+        }
+    }
+}
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 457fedd2d8a..8000e60f64d 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -743,7 +743,7 @@ class RustBuild(object):
         """
         return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap")
 
-    def build_bootstrap(self):
+    def build_bootstrap(self, color):
         """Build bootstrap"""
         print("Building rustbuild")
         build_dir = os.path.join(self.build_dir, "bootstrap")
@@ -800,6 +800,11 @@ class RustBuild(object):
         if self.get_toml("metrics", "build"):
             args.append("--features")
             args.append("build-metrics")
+        if color == "always":
+            args.append("--color=always")
+        elif color == "never":
+            args.append("--color=never")
+
         run(args, env=env, verbose=self.verbose)
 
     def build_triple(self):
@@ -862,6 +867,7 @@ def bootstrap(help_triggered):
     parser = argparse.ArgumentParser(description='Build rust')
     parser.add_argument('--config')
     parser.add_argument('--build')
+    parser.add_argument('--color', choices=['always', 'never', 'auto'])
     parser.add_argument('--clean', action='store_true')
     parser.add_argument('-v', '--verbose', action='count', default=0)
 
@@ -930,7 +936,7 @@ def bootstrap(help_triggered):
     # Fetch/build the bootstrap
     build.download_toolchain()
     sys.stdout.flush()
-    build.build_bootstrap()
+    build.build_bootstrap(args.color)
     sys.stdout.flush()
 
     # Run the bootstrap
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index b4b7790eebb..5d0756d30fb 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -983,42 +983,51 @@ table,
 	font-weight: normal;
 }
 
-body.blur > :not(#help) {
-	filter: blur(8px);
-	-webkit-filter: blur(8px);
-	opacity: .7;
+.popover {
+	font-size: 1rem;
+	position: absolute;
+	right: 0;
+	z-index: 2;
+	display: block;
+	margin-top: 7px;
+	border-radius: 3px;
+	border: 1px solid;
+	font-size: 1rem;
 }
 
-#help {
-	width: 100%;
-	height: 100vh;
-	position: fixed;
-	top: 0;
-	left: 0;
-	display: flex;
-	justify-content: center;
-	align-items: center;
+/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */
+.popover::before {
+	content: '';
+	position: absolute;
+	right: 11px;
+	border: solid;
+	border-width: 1px 1px 0 0;
+	display: inline-block;
+	padding: 4px;
+	transform: rotate(-45deg);
+	top: -5px;
 }
-#help > div {
-	flex: 0 0 auto;
-	box-shadow: 0 0 6px rgba(0,0,0,.2);
-	width: 550px;
-	height: auto;
-	border: 1px solid;
+
+#help-button .popover {
+	max-width: 600px;
 }
-#help dt {
+
+#help-button .popover::before {
+	right: 48px;
+}
+
+#help-button dt {
 	float: left;
 	clear: left;
 	display: block;
 	margin-right: 0.5rem;
 }
-#help span.top, #help span.bottom {
+#help-button span.top, #help-button span.bottom {
 	text-align: center;
 	display: block;
 	font-size: 1.125rem;
-
 }
-#help span.top {
+#help-button span.top {
 	text-align: center;
 	display: block;
 	margin: 10px 0;
@@ -1026,17 +1035,17 @@ body.blur > :not(#help) {
 	padding-bottom: 4px;
 	margin-bottom: 6px;
 }
-#help span.bottom {
+#help-button span.bottom {
 	clear: both;
 	border-top: 1px solid;
 }
-#help dd { margin: 5px 35px; }
-#help .infos { padding-left: 0; }
-#help h1, #help h2 { margin-top: 0; }
-#help > div div {
+.side-by-side {
+	text-align: initial;
+}
+.side-by-side > div {
 	width: 50%;
 	float: left;
-	padding: 0 20px 20px 17px;;
+	padding: 0 20px 20px 17px;
 }
 
 .item-info .stab {
@@ -1391,7 +1400,7 @@ pre.rust {
 #copy-path {
 	height: 34px;
 }
-#settings-menu > a, #help-button, #copy-path {
+#settings-menu > a, #help-button > button, #copy-path {
 	padding: 5px;
 	width: 33px;
 	border: 1px solid;
@@ -1401,9 +1410,8 @@ pre.rust {
 #settings-menu {
 	padding: 0;
 }
-#settings-menu > a {
+#settings-menu > a, #help-button > button {
 	padding: 5px;
-	width: 100%;
 	height: 100%;
 	display: block;
 }
@@ -1420,7 +1428,7 @@ pre.rust {
 	animation: rotating 2s linear infinite;
 }
 
-#help-button {
+#help-button > button {
 	font-family: "Fira Sans", Arial, sans-serif;
 	text-align: center;
 	/* Rare exception to specifying font sizes in rem. Since this is acting
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
index 1cd8e39e036..e531e6ce6bb 100644
--- a/src/librustdoc/html/static/css/settings.css
+++ b/src/librustdoc/html/static/css/settings.css
@@ -86,27 +86,6 @@ input:checked + .slider:before {
 	display: block;
 }
 
-div#settings {
-	position: absolute;
-	right: 0;
-	z-index: 1;
-	display: block;
-	margin-top: 7px;
-	border-radius: 3px;
-	border: 1px solid;
-}
 #settings .setting-line {
 	margin: 1.2em 0.6em;
 }
-/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */
-div#settings::before {
-	content: '';
-	position: absolute;
-	right: 11px;
-	border: solid;
-	border-width: 1px 1px 0 0;
-	display: inline-block;
-	padding: 4px;
-	transform: rotate(-45deg);
-	top: -5px;
-}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 5b37ecf19da..b7d0db1f002 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -5,7 +5,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 
 /* General structure and fonts */
 
-body, #settings-menu #settings, #settings-menu #settings::before {
+body, .popover, .popover::before {
 	background-color: #0f1419;
 	color: #c5c5c5;
 }
@@ -567,7 +567,7 @@ kbd {
 	box-shadow: inset 0 -1px 0 #5c6773;
 }
 
-#settings-menu > a, #help-button {
+#settings-menu > a, #help-button > button {
 	border-color: #5c6773;
 	background-color: #0f1419;
 	color: #fff;
@@ -577,7 +577,8 @@ kbd {
 	filter: invert(100);
 }
 
-#settings-menu #settings, #settings-menu #settings::before {
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
 	border-color: #5c6773;
 }
 
@@ -592,7 +593,7 @@ kbd {
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button:hover, #help-button:focus {
+#help-button > button:hover, #help-button > button:focus {
 	border-color: #e0e0e0;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index ffb59f7762b..eb64ef3e771 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -1,4 +1,4 @@
-body, #settings-menu #settings, #settings-menu #settings::before {
+body, .popover, .popover::before {
 	background-color: #353535;
 	color: #ddd;
 }
@@ -442,18 +442,19 @@ kbd {
 	box-shadow: inset 0 -1px 0 #c6cbd1;
 }
 
-#settings-menu > a, #help-button {
+#settings-menu > a, #help-button > button {
 	border-color: #e0e0e0;
 	background: #f0f0f0;
 	color: #000;
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button:hover, #help-button:focus {
+#help-button > button:hover, #help-button > button:focus {
 	border-color: #ffb900;
 }
 
-#settings-menu #settings, #settings-menu #settings::before {
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
 	border-color: #d2d2d2;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index ba798ee2a0e..00cdf835897 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -1,6 +1,6 @@
 /* General structure and fonts */
 
-body, #settings-menu #settings, #settings-menu #settings::before {
+body, .popover, .popover::before {
 	background-color: white;
 	color: black;
 }
@@ -427,17 +427,18 @@ kbd {
 	box-shadow: inset 0 -1px 0 #c6cbd1;
 }
 
-#settings-menu > a, #help-button {
+#settings-menu > a, #help-button > button {
 	border-color: #e0e0e0;
 	background-color: #fff;
 }
 
 #settings-menu > a:hover, #settings-menu > a:focus,
-#help-button:hover, #help-button:focus {
+#help-button > button:hover, #help-button > button:focus {
 	border-color: #717171;
 }
 
-#settings-menu #settings, #settings-menu #settings::before {
+.popover, .popover::before,
+#help-button span.top, #help-button span.bottom {
 	border-color: #DDDDDD;
 }
 
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index b320db91046..70dbfd44425 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -63,6 +63,24 @@ function showMain() {
     removeClass(document.getElementById(MAIN_ID), "hidden");
 }
 
+function elemIsInParent(elem, parent) {
+    while (elem && elem !== document.body) {
+        if (elem === parent) {
+            return true;
+        }
+        elem = elem.parentElement;
+    }
+    return false;
+}
+
+function blurHandler(event, parentElem, hideCallback) {
+    if (!elemIsInParent(document.activeElement, parentElem) &&
+        !elemIsInParent(event.relatedTarget, parentElem)
+    ) {
+        hideCallback();
+    }
+}
+
 (function() {
     window.rootPath = getVar("root-path");
     window.currentCrate = getVar("current-crate");
@@ -104,20 +122,21 @@ const MAIN_ID = "main-content";
 const SETTINGS_BUTTON_ID = "settings-menu";
 const ALTERNATIVE_DISPLAY_ID = "alternative-display";
 const NOT_DISPLAYED_ID = "not-displayed";
+const HELP_BUTTON_ID = "help-button";
 
 function getSettingsButton() {
     return document.getElementById(SETTINGS_BUTTON_ID);
 }
 
+function getHelpButton() {
+    return document.getElementById(HELP_BUTTON_ID);
+}
+
 // Returns the current URL without any query parameter or hash.
 function getNakedUrl() {
     return window.location.href.split("?")[0].split("#")[0];
 }
 
-window.hideSettings = () => {
-    // Does nothing by default.
-};
-
 /**
  * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
  * doesn't have a parent node.
@@ -381,55 +400,16 @@ function loadCss(cssFileName) {
         openParentDetails(document.getElementById(id));
     }
 
-    function getHelpElement(build) {
-        if (build) {
-            buildHelperPopup();
-        }
-        return document.getElementById("help");
-    }
-
-    /**
-     * Show the help popup.
-     *
-     * @param {boolean} display    - Whether to show or hide the popup
-     * @param {Event}   ev         - The event that triggered this call
-     * @param {Element} [help]     - The help element if it already exists
-     */
-    function displayHelp(display, ev, help) {
-        if (display) {
-            help = help ? help : getHelpElement(true);
-            if (hasClass(help, "hidden")) {
-                ev.preventDefault();
-                removeClass(help, "hidden");
-                addClass(document.body, "blur");
-            }
-        } else {
-            // No need to build the help popup if we want to hide it in case it hasn't been
-            // built yet...
-            help = help ? help : getHelpElement(false);
-            if (help && !hasClass(help, "hidden")) {
-                ev.preventDefault();
-                addClass(help, "hidden");
-                removeClass(document.body, "blur");
-            }
-        }
-    }
-
     function handleEscape(ev) {
         searchState.clearInputTimeout();
-        const help = getHelpElement(false);
-        if (help && !hasClass(help, "hidden")) {
-            displayHelp(false, ev, help);
-        } else {
-            switchDisplayedElement(null);
-            if (browserSupportsHistoryApi()) {
-                history.replaceState(null, window.currentCrate + " - Rust",
-                    getNakedUrl() + window.location.hash);
-            }
-            ev.preventDefault();
+        switchDisplayedElement(null);
+        if (browserSupportsHistoryApi()) {
+            history.replaceState(null, window.currentCrate + " - Rust",
+                getNakedUrl() + window.location.hash);
         }
+        ev.preventDefault();
         searchState.defocus();
-        window.hideSettings();
+        window.hidePopoverMenus();
     }
 
     const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
@@ -453,7 +433,6 @@ function loadCss(cssFileName) {
 
             case "s":
             case "S":
-                displayHelp(false, ev);
                 ev.preventDefault();
                 searchState.focus();
                 break;
@@ -465,7 +444,7 @@ function loadCss(cssFileName) {
                 break;
 
             case "?":
-                displayHelp(true, ev);
+                showHelp();
                 break;
 
             default:
@@ -796,9 +775,6 @@ function loadCss(cssFileName) {
             elem.addEventListener("click", f);
         }
     }
-    handleClick("help-button", ev => {
-        displayHelp(true, ev);
-    });
     handleClick(MAIN_ID, () => {
         hideSidebar();
     });
@@ -842,24 +818,16 @@ function loadCss(cssFileName) {
         });
     }
 
-    let buildHelperPopup = () => {
-        const popup = document.createElement("aside");
-        addClass(popup, "hidden");
-        popup.id = "help";
-
-        popup.addEventListener("click", ev => {
-            if (ev.target === popup) {
-                // Clicked the blurred zone outside the help popup; dismiss help.
-                displayHelp(false, ev);
-            }
-        });
+    function helpBlurHandler(event) {
+        blurHandler(event, getHelpButton(), window.hidePopoverMenus);
+    }
 
+    function buildHelpMenu() {
         const book_info = document.createElement("span");
         book_info.className = "top";
         book_info.innerHTML = "You can find more information in \
             <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
 
-        const container = document.createElement("div");
         const shortcuts = [
             ["?", "Show this help dialog"],
             ["S", "Focus the search field"],
@@ -895,24 +863,85 @@ function loadCss(cssFileName) {
         addClass(div_infos, "infos");
         div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
 
-        container.appendChild(book_info);
-        container.appendChild(div_shortcuts);
-        container.appendChild(div_infos);
-
         const rustdoc_version = document.createElement("span");
         rustdoc_version.className = "bottom";
         const rustdoc_version_code = document.createElement("code");
         rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");
         rustdoc_version.appendChild(rustdoc_version_code);
 
+        const container = document.createElement("div");
+        container.className = "popover";
+        container.style.display = "none";
+
+        const side_by_side = document.createElement("div");
+        side_by_side.className = "side-by-side";
+        side_by_side.appendChild(div_shortcuts);
+        side_by_side.appendChild(div_infos);
+
+        container.appendChild(book_info);
+        container.appendChild(side_by_side);
         container.appendChild(rustdoc_version);
 
-        popup.appendChild(container);
-        insertAfter(popup, document.querySelector("main"));
-        // So that it's only built once and then it'll do nothing when called!
-        buildHelperPopup = () => {};
+        const help_button = getHelpButton();
+        help_button.appendChild(container);
+
+        container.onblur = helpBlurHandler;
+        container.onclick = event => {
+            event.preventDefault();
+        };
+        help_button.onblur = helpBlurHandler;
+        help_button.children[0].onblur = helpBlurHandler;
+
+        return container;
+    }
+
+    /**
+     * Hide all the popover menus.
+     */
+    window.hidePopoverMenus = function() {
+        onEachLazy(document.querySelectorAll(".search-container .popover"), elem => {
+            elem.style.display = "none";
+        });
     };
 
+    /**
+     * Returns the help menu element (not the button).
+     *
+     * @param {boolean} buildNeeded - If this argument is `false`, the help menu element won't be
+     *                                built if it doesn't exist.
+     *
+     * @return {HTMLElement}
+     */
+    function getHelpMenu(buildNeeded) {
+        let menu = getHelpButton().querySelector(".popover");
+        if (!menu && buildNeeded) {
+            menu = buildHelpMenu();
+        }
+        return menu;
+    }
+
+    /**
+     * Show the help popup menu.
+     */
+    function showHelp() {
+        const menu = getHelpMenu(true);
+        if (menu.style.display === "none") {
+            menu.style.display = "";
+        }
+    }
+
+    document.querySelector(`#${HELP_BUTTON_ID} > button`).addEventListener("click", event => {
+        const target = event.target;
+        if (target.tagName !== "BUTTON" || target.parentElement.id !== HELP_BUTTON_ID) {
+            return;
+        }
+        const menu = getHelpMenu(true);
+        const shouldShowHelp = menu.style.display === "none";
+        if (shouldShowHelp) {
+            showHelp();
+        }
+    });
+
     setMobileTopbar();
     addSidebarItems();
     addSidebarCrates();
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 41bf0ec8955..797b931afc6 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -1,6 +1,6 @@
 // Local js definitions:
 /* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */
-/* global addClass, removeClass, onEach, onEachLazy */
+/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */
 /* global MAIN_ID, getVar, getSettingsButton */
 
 "use strict";
@@ -209,6 +209,7 @@
         const innerHTML = `<div class="settings">${buildSettingsPageSections(settings)}</div>`;
         const el = document.createElement(elementKind);
         el.id = "settings";
+        el.className = "popover";
         el.innerHTML = innerHTML;
 
         if (isSettingsPage) {
@@ -226,23 +227,8 @@
         settingsMenu.style.display = "";
     }
 
-    function elemIsInParent(elem, parent) {
-        while (elem && elem !== document.body) {
-            if (elem === parent) {
-                return true;
-            }
-            elem = elem.parentElement;
-        }
-        return false;
-    }
-
-    function blurHandler(event) {
-        const settingsButton = getSettingsButton();
-        if (!elemIsInParent(document.activeElement, settingsButton) &&
-            !elemIsInParent(event.relatedTarget, settingsButton)
-        ) {
-            window.hideSettings();
-        }
+    function settingsBlurHandler(event) {
+        blurHandler(event, getSettingsButton(), window.hidePopoverMenus);
     }
 
     if (isSettingsPage) {
@@ -254,26 +240,24 @@
         // We replace the existing "onclick" callback.
         const settingsButton = getSettingsButton();
         const settingsMenu = document.getElementById("settings");
-        window.hideSettings = function() {
-            settingsMenu.style.display = "none";
-        };
         settingsButton.onclick = function(event) {
             if (elemIsInParent(event.target, settingsMenu)) {
                 return;
             }
             event.preventDefault();
-            if (settingsMenu.style.display !== "none") {
-                window.hideSettings();
-            } else {
+            const shouldDisplaySettings = settingsMenu.style.display === "none";
+
+            window.hidePopoverMenus();
+            if (shouldDisplaySettings) {
                 displaySettings();
             }
         };
-        settingsButton.onblur = blurHandler;
-        settingsButton.querySelector("a").onblur = blurHandler;
+        settingsButton.onblur = settingsBlurHandler;
+        settingsButton.querySelector("a").onblur = settingsBlurHandler;
         onEachLazy(settingsMenu.querySelectorAll("input"), el => {
-            el.onblur = blurHandler;
+            el.onblur = settingsBlurHandler;
         });
-        settingsMenu.onblur = blurHandler;
+        settingsMenu.onblur = settingsBlurHandler;
     }
 
     // We now wait a bit for the web browser to end re-computing the DOM...
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index c4999e2c74f..dfb3e4e6a2c 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -119,7 +119,9 @@
                                 spellcheck="false" {# -#}
                                 placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
                                 type="search"> {#- -#}
-                            <button type="button" id="help-button" title="help">?</button> {#- -#}
+                            <div id="help-button" title="help" tabindex="-1"> {#- -#}
+                                <button type="button">?</button> {#- -#}
+                            </div> {#- -#}
                             <div id="settings-menu" tabindex="-1">
                                 <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
                                     <img width="22" height="22" alt="Change settings" {# -#}
diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml
index 8713bf65c84..d083b0ae0c9 100644
--- a/src/test/rustdoc-gui/escape-key.goml
+++ b/src/test/rustdoc-gui/escape-key.goml
@@ -21,17 +21,6 @@ wait-for: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content hidden"})
 assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
 
-// Now let's check that when the help popup is displayed and we press Escape, it doesn't
-// hide the search results too.
-click: "#help-button"
-assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
-assert-attribute: ("#help", {"class": ""})
-press-key: "Escape"
-wait-for: "#alternative-display #search"
-assert-attribute: ("#help", {"class": "hidden"})
-assert-attribute: ("#main-content", {"class": "content hidden"})
-assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
-
 // Check that Escape hides the search results when a search result is focused.
 focus: ".search-input"
 assert: ".search-input:focus"
@@ -39,7 +28,6 @@ press-key: "ArrowDown"
 assert-false: ".search-input:focus"
 assert: "#results a:focus"
 press-key: "Escape"
-assert-attribute: ("#help", {"class": "hidden"})
 wait-for: "#not-displayed #search"
 assert-false: "#alternative-display #search"
 assert-attribute: ("#main-content", {"class": "content"})
diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml
new file mode 100644
index 00000000000..ba2986e969a
--- /dev/null
+++ b/src/test/rustdoc-gui/pocket-menu.goml
@@ -0,0 +1,72 @@
+// This test ensures that the "pocket menus" are working as expected.
+goto: file://|DOC_PATH|/test_docs/index.html
+// First we check that the help menu doesn't exist yet.
+assert-false: "#help-button .popover"
+// Then we display the help menu.
+click: "#help-button"
+assert: "#help-button .popover"
+assert-css: ("#help-button .popover", {"display": "block"})
+
+// Now we click somewhere else on the page to ensure it is handling the blur event
+// correctly.
+click: ".sidebar"
+assert-css: ("#help-button .popover", {"display": "none"})
+
+// Now we will check that we cannot have two "pocket menus" displayed at the same time.
+click: "#help-button"
+assert-css: ("#help-button .popover", {"display": "block"})
+click: "#settings-menu"
+assert-css: ("#help-button .popover", {"display": "none"})
+assert-css: ("#settings-menu .popover", {"display": "block"})
+
+// Now the other way.
+click: "#help-button"
+assert-css: ("#help-button .popover", {"display": "block"})
+assert-css: ("#settings-menu .popover", {"display": "none"})
+
+// We check the borders color now:
+
+// Ayu theme
+local-storage: {
+    "rustdoc-theme": "ayu",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+    "#help-button .popover",
+    {"display": "block", "border-color": "rgb(92, 103, 115)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+
+// Dark theme
+local-storage: {
+    "rustdoc-theme": "dark",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+    "#help-button .popover",
+    {"display": "block", "border-color": "rgb(210, 210, 210)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
+
+// Light theme
+local-storage: {
+    "rustdoc-theme": "light",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+click: "#help-button"
+assert-css: (
+    "#help-button .popover",
+    {"display": "block", "border-color": "rgb(221, 221, 221)"},
+)
+compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
+compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml
index 37a7c166294..1f20a0eaa99 100644
--- a/src/test/rustdoc-gui/shortcuts.goml
+++ b/src/test/rustdoc-gui/shortcuts.goml
@@ -8,7 +8,6 @@ press-key: "Escape"
 assert-false: "input.search-input:focus"
 // We now check for the help popup.
 press-key: "?"
-assert-css: ("#help", {"display": "flex"})
-assert-false: "#help.hidden"
+assert-css: ("#help-button .popover", {"display": "block"})
 press-key: "Escape"
-assert-css: ("#help.hidden", {"display": "none"})
+assert-css: ("#help-button .popover", {"display": "none"})
diff --git a/src/test/rustdoc/generic_const_exprs.rs b/src/test/rustdoc/generic_const_exprs.rs
new file mode 100644
index 00000000000..6ff59163975
--- /dev/null
+++ b/src/test/rustdoc/generic_const_exprs.rs
@@ -0,0 +1,24 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/92859>.
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+#![crate_name = "foo"]
+
+// @has 'foo/trait.Foo.html'
+
+pub trait Foo: Sized {
+    const WIDTH: usize;
+
+    fn arrayify(self) -> [Self; Self::WIDTH];
+}
+
+impl<T: Sized> Foo for T {
+    const WIDTH: usize = 1;
+
+    // @has - '//*[@id="tymethod.arrayify"]/*[@class="code-header"]' \
+    // 'fn arrayify(self) -> [Self; Self::WIDTH]'
+    fn arrayify(self) -> [Self; Self::WIDTH] {
+        [self]
+    }
+}
diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
index 817d8531da9..d6f63d44ba6 100644
--- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
@@ -16,14 +16,14 @@ use rustc_session::{parse::ParseSess, SessionDiagnostic};
 use rustc_span::Span;
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "parser-expect-path")]
+#[error(parser::expect_path)]
 struct DeriveSessionDiagnostic {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[note(slug = "note")]
+#[note(parser::add_paren)]
 struct Note {
     #[primary_span]
     span: Span,
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 84d5de17309..7bec1897fa5 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -26,15 +26,15 @@ use rustc_errors::Applicability;
 extern crate rustc_session;
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "hello-world")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct Hello {}
 
 #[derive(SessionDiagnostic)]
-#[warning(code = "E0123", slug = "hello-world")]
+#[warning(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct HelloWarn {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 //~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs
 enum SessionDiagnosticOnEnum {
     Foo,
@@ -42,13 +42,13 @@ enum SessionDiagnosticOnEnum {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 #[error = "E0123"]
 //~^ ERROR `#[error = ...]` is not a valid attribute
 struct WrongStructAttrStyle {}
 
 #[derive(SessionDiagnostic)]
-#[nonsense(code = "E0123", slug = "foo")]
+#[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
 //~^ ERROR `#[nonsense(...)]` is not a valid attribute
 //~^^ ERROR diagnostic kind not specified
 //~^^^ ERROR cannot find attribute `nonsense` in this scope
@@ -57,31 +57,39 @@ struct InvalidStructAttr {}
 #[derive(SessionDiagnostic)]
 #[error("E0123")]
 //~^ ERROR `#[error("...")]` is not a valid attribute
-//~^^ ERROR `slug` not specified
+//~^^ ERROR diagnostic slug not specified
 struct InvalidLitNestedAttr {}
 
 #[derive(SessionDiagnostic)]
-#[error(nonsense, code = "E0123", slug = "foo")]
-//~^ ERROR `#[error(nonsense)]` is not a valid attribute
+#[error(nonsense, code = "E0123")]
+//~^ ERROR cannot find value `nonsense` in module `rustc_errors::fluent`
 struct InvalidNestedStructAttr {}
 
 #[derive(SessionDiagnostic)]
 #[error(nonsense("foo"), code = "E0123", slug = "foo")]
 //~^ ERROR `#[error(nonsense(...))]` is not a valid attribute
+//~^^ ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr1 {}
 
 #[derive(SessionDiagnostic)]
 #[error(nonsense = "...", code = "E0123", slug = "foo")]
 //~^ ERROR `#[error(nonsense = ...)]` is not a valid attribute
+//~^^ ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr2 {}
 
 #[derive(SessionDiagnostic)]
 #[error(nonsense = 4, code = "E0123", slug = "foo")]
 //~^ ERROR `#[error(nonsense = ...)]` is not a valid attribute
+//~^^ ERROR diagnostic slug not specified
 struct InvalidNestedStructAttr3 {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
+//~^ ERROR `#[error(slug = ...)]` is not a valid attribute
+struct InvalidNestedStructAttr4 {}
+
+#[derive(SessionDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct WrongPlaceField {
     #[suggestion = "bar"]
     //~^ ERROR `#[suggestion = ...]` is not a valid attribute
@@ -89,44 +97,45 @@ struct WrongPlaceField {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[error(code = "E0456", slug = "bar")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
 //~^^^ ERROR specified multiple times
 struct ErrorSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[warning(code = "E0293", slug = "bar")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
 //~^^^ ERROR specified multiple times
 struct WarnSpecifiedAfterError {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456", code = "E0457", slug = "bar")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
 //~^ ERROR specified multiple times
 struct CodeSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456", slug = "foo", slug = "bar")]
-//~^ ERROR specified multiple times
+#[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
+//~^ ERROR `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute
 struct SlugSpecifiedTwice {}
 
 #[derive(SessionDiagnostic)]
 struct KindNotProvided {} //~ ERROR diagnostic kind not specified
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456")] //~ ERROR `slug` not specified
+#[error(code = "E0456")]
+//~^ ERROR diagnostic slug not specified
 struct SlugNotProvided {}
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound)]
 struct CodeNotProvided {}
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct MessageWrongType {
     #[primary_span]
     //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span`
@@ -134,7 +143,7 @@ struct MessageWrongType {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct InvalidPathFieldAttr {
     #[nonsense]
     //~^ ERROR `#[nonsense]` is not a valid attribute
@@ -143,34 +152,34 @@ struct InvalidPathFieldAttr {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithField {
     name: String,
-    #[label = "bar"]
+    #[label(typeck::label)]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithMessageAppliedToField {
-    #[label = "bar"]
-    //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
+    #[label(typeck::label)]
+    //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span`
     name: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithNonexistentField {
-    #[suggestion(message = "bar", code = "{name}")]
+    #[suggestion(typeck::suggestion, code = "{name}")]
     //~^ ERROR `name` doesn't refer to a field on this type
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
 //~^ ERROR invalid format string: expected `'}'`
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorMissingClosingBrace {
-    #[suggestion(message = "bar", code = "{name")]
+    #[suggestion(typeck::suggestion, code = "{name")]
     suggestion: (Span, Applicability),
     name: String,
     val: usize,
@@ -178,48 +187,48 @@ struct ErrorMissingClosingBrace {
 
 #[derive(SessionDiagnostic)]
 //~^ ERROR invalid format string: unmatched `}`
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorMissingOpeningBrace {
-    #[suggestion(message = "bar", code = "name}")]
+    #[suggestion(typeck::suggestion, code = "name}")]
     suggestion: (Span, Applicability),
     name: String,
     val: usize,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct LabelOnSpan {
-    #[label = "bar"]
+    #[label(typeck::label)]
     sp: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct LabelOnNonSpan {
-    #[label = "bar"]
-    //~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
+    #[label(typeck::label)]
+    //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span`
     id: u32,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct Suggest {
-    #[suggestion(message = "bar", code = "This is the suggested code")]
-    #[suggestion_short(message = "qux", code = "This is the suggested code")]
-    #[suggestion_hidden(message = "foobar", code = "This is the suggested code")]
-    #[suggestion_verbose(message = "fooqux", code = "This is the suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is the suggested code")]
+    #[suggestion_short(typeck::suggestion, code = "This is the suggested code")]
+    #[suggestion_hidden(typeck::suggestion, code = "This is the suggested code")]
+    #[suggestion_verbose(typeck::suggestion, code = "This is the suggested code")]
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithoutCode {
-    #[suggestion(message = "bar")]
+    #[suggestion(typeck::suggestion)]
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithBadKey {
     #[suggestion(nonsense = "bar")]
     //~^ ERROR `#[suggestion(nonsense = ...)]` is not a valid attribute
@@ -227,7 +236,7 @@ struct SuggestWithBadKey {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithShorthandMsg {
     #[suggestion(msg = "bar")]
     //~^ ERROR `#[suggestion(msg = ...)]` is not a valid attribute
@@ -235,91 +244,91 @@ struct SuggestWithShorthandMsg {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithoutMsg {
     #[suggestion(code = "bar")]
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithTypesSwapped {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     suggestion: (Applicability, Span),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithWrongTypeApplicabilityOnly {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     //~^ ERROR wrong field type for suggestion
     suggestion: Applicability,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithSpanOnly {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     suggestion: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithDuplicateSpanAndApplicability {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
     suggestion: (Span, Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct SuggestWithDuplicateApplicabilityAndSpan {
-    #[suggestion(message = "bar", code = "This is suggested code")]
+    #[suggestion(typeck::suggestion, code = "This is suggested code")]
     //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
     suggestion: (Applicability, Applicability, Span),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct WrongKindOfAnnotation {
-    #[label("bar")]
-    //~^ ERROR `#[label(...)]` is not a valid attribute
+    #[label = "bar"]
+    //~^ ERROR `#[label = ...]` is not a valid attribute
     z: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct OptionsInErrors {
-    #[label = "bar"]
+    #[label(typeck::label)]
     label: Option<Span>,
-    #[suggestion(message = "bar")]
+    #[suggestion(typeck::suggestion)]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0456", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
 struct MoveOutOfBorrowError<'tcx> {
     name: Ident,
     ty: Ty<'tcx>,
     #[primary_span]
-    #[label = "bar"]
+    #[label(typeck::label)]
     span: Span,
-    #[label = "qux"]
+    #[label(typeck::label)]
     other_span: Span,
-    #[suggestion(message = "bar", code = "{name}.clone()")]
+    #[suggestion(typeck::suggestion, code = "{name}.clone()")]
     opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithLifetime<'a> {
-    #[label = "bar"]
+    #[label(typeck::label)]
     span: Span,
     name: &'a str,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithDefaultLabelAttr<'a> {
     #[label]
     span: Span,
@@ -328,7 +337,7 @@ struct ErrorWithDefaultLabelAttr<'a> {
 
 #[derive(SessionDiagnostic)]
 //~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ArgFieldWithoutSkip {
     #[primary_span]
     span: Span,
@@ -336,7 +345,7 @@ struct ArgFieldWithoutSkip {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ArgFieldWithSkip {
     #[primary_span]
     span: Span,
@@ -347,132 +356,132 @@ struct ArgFieldWithSkip {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithSpannedNote {
     #[note]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithSpannedNoteCustom {
-    #[note = "bar"]
+    #[note(typeck::note)]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 #[note]
 struct ErrorWithNote {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[note = "bar"]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[note(typeck::note)]
 struct ErrorWithNoteCustom {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithSpannedHelp {
     #[help]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithSpannedHelpCustom {
-    #[help = "bar"]
+    #[help(typeck::help)]
     span: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 #[help]
 struct ErrorWithHelp {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
-#[help = "bar"]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+#[help(typeck::help)]
 struct ErrorWithHelpCustom {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
 #[help]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithHelpWrongOrder {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[help = "bar"]
-#[error(code = "E0123", slug = "foo")]
+#[help(typeck::help)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithHelpCustomWrongOrder {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
 #[note]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithNoteWrongOrder {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[note = "bar"]
-#[error(code = "E0123", slug = "foo")]
+#[note(typeck::note)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ErrorWithNoteCustomWrongOrder {
     val: String,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ApplicabilityInBoth {
-    #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
+    #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
     //~^ ERROR applicability cannot be set in both the field and attribute
     suggestion: (Span, Applicability),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct InvalidApplicability {
-    #[suggestion(message = "bar", code = "...", applicability = "batman")]
+    #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
     //~^ ERROR invalid applicability
     suggestion: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct ValidApplicability {
-    #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
+    #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
     suggestion: Span,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct NoApplicability {
-    #[suggestion(message = "bar", code = "...")]
+    #[suggestion(typeck::suggestion, code = "...")]
     suggestion: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[note(slug = "note")]
+#[note(parser::add_paren)]
 struct Note;
 
 #[derive(SessionDiagnostic)]
-#[error(slug = "subdiagnostic")]
+#[error(typeck::ambiguous_lifetime_bound)]
 struct Subdiagnostic {
     #[subdiagnostic]
     note: Note,
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct VecField {
     #[primary_span]
     #[label]
@@ -480,23 +489,47 @@ struct VecField {
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct UnitField {
     #[primary_span]
     spans: Span,
     #[help]
     foo: (),
-    #[help = "a"]
+    #[help(typeck::help)]
     bar: (),
 }
 
 #[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 struct OptUnitField {
     #[primary_span]
     spans: Span,
     #[help]
     foo: Option<()>,
-    #[help = "a"]
+    #[help(typeck::help)]
     bar: Option<()>,
 }
+
+#[derive(SessionDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct LabelWithTrailingPath {
+    #[label(typeck::label, foo)]
+    //~^ ERROR `#[label(...)]` is not a valid attribute
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct LabelWithTrailingNameValue {
+    #[label(typeck::label, foo = "...")]
+    //~^ ERROR `#[label(...)]` is not a valid attribute
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+struct LabelWithTrailingList {
+    #[label(typeck::label, foo("..."))]
+    //~^ ERROR `#[label(...)]` is not a valid attribute
+    span: Span,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 85ea44ec278..0d9690e1f5a 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,7 +1,7 @@
 error: `#[derive(SessionDiagnostic)]` can only be used on structs
   --> $DIR/diagnostic-derive.rs:37:1
    |
-LL | / #[error(code = "E0123", slug = "foo")]
+LL | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
 LL | | enum SessionDiagnosticOnEnum {
 LL | |     Foo,
@@ -18,15 +18,15 @@ LL | #[error = "E0123"]
 error: `#[nonsense(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:51:1
    |
-LL | #[nonsense(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: only `error` and `warning` are valid attributes
+   = help: only `error`, `warning`, `help` and `note` are valid attributes
 
 error: diagnostic kind not specified
   --> $DIR/diagnostic-derive.rs:51:1
    |
-LL | / #[nonsense(code = "E0123", slug = "foo")]
+LL | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
 LL | |
 LL | |
@@ -40,8 +40,10 @@ error: `#[error("...")]` is not a valid attribute
    |
 LL | #[error("E0123")]
    |         ^^^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
-error: `slug` not specified
+error: diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:58:1
    |
 LL | / #[error("E0123")]
@@ -50,183 +52,215 @@ LL | |
 LL | | struct InvalidLitNestedAttr {}
    | |______________________________^
    |
-   = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
-
-error: `#[error(nonsense)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:64:9
-   |
-LL | #[error(nonsense, code = "E0123", slug = "foo")]
-   |         ^^^^^^^^
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense(...))]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:69:9
    |
 LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
+
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:69:1
+   |
+LL | / #[error(nonsense("foo"), code = "E0123", slug = "foo")]
+LL | |
+LL | |
+LL | | struct InvalidNestedStructAttr1 {}
+   | |__________________________________^
+   |
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:74:9
+  --> $DIR/diagnostic-derive.rs:75:9
    |
 LL | #[error(nonsense = "...", code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^^^^^
    |
-   = help: only `slug` and `code` are valid nested attributes
+   = help: first argument of the attribute should be the diagnostic slug
+
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:75:1
+   |
+LL | / #[error(nonsense = "...", code = "E0123", slug = "foo")]
+LL | |
+LL | |
+LL | | struct InvalidNestedStructAttr2 {}
+   | |__________________________________^
+   |
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:79:9
+  --> $DIR/diagnostic-derive.rs:81:9
    |
 LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
-error: `#[suggestion = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:86:5
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:81:1
    |
-LL |     #[suggestion = "bar"]
-   |     ^^^^^^^^^^^^^^^^^^^^^
+LL | / #[error(nonsense = 4, code = "E0123", slug = "foo")]
+LL | |
+LL | |
+LL | | struct InvalidNestedStructAttr3 {}
+   | |__________________________________^
    |
-   = help: only `label`, `note` and `help` are valid field attributes
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
-error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:93:1
+error: `#[error(slug = ...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:87:59
    |
-LL | #[error(code = "E0456", slug = "bar")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
+   |                                                           ^^^^^^^^^^^^
    |
-note: previously specified here
-  --> $DIR/diagnostic-derive.rs:92:1
+   = help: only `code` is a valid nested attributes following the slug
+
+error: `#[suggestion = ...]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:94:5
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion = "bar"]
+   |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:93:16
+  --> $DIR/diagnostic-derive.rs:101:1
    |
-LL | #[error(code = "E0456", slug = "bar")]
-   |                ^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:92:16
+  --> $DIR/diagnostic-derive.rs:100:1
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   |                ^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:93:32
+  --> $DIR/diagnostic-derive.rs:101:1
    |
-LL | #[error(code = "E0456", slug = "bar")]
-   |                                ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:92:32
+  --> $DIR/diagnostic-derive.rs:100:1
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   |                                ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:1
+  --> $DIR/diagnostic-derive.rs:101:50
    |
-LL | #[warning(code = "E0293", slug = "bar")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
+   |                                                  ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:1
+  --> $DIR/diagnostic-derive.rs:100:50
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   |                                                  ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:18
+  --> $DIR/diagnostic-derive.rs:109:1
    |
-LL | #[warning(code = "E0293", slug = "bar")]
-   |                  ^^^^^^^
+LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:16
+  --> $DIR/diagnostic-derive.rs:108:1
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   |                ^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:34
+  --> $DIR/diagnostic-derive.rs:109:1
    |
-LL | #[warning(code = "E0293", slug = "bar")]
-   |                                  ^^^^^
+LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:32
+  --> $DIR/diagnostic-derive.rs:108:1
    |
-LL | #[error(code = "E0123", slug = "foo")]
-   |                                ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:108:32
+  --> $DIR/diagnostic-derive.rs:109:52
    |
-LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
-   |                                ^^^^^^^
+LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
+   |                                                    ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:108:16
+  --> $DIR/diagnostic-derive.rs:108:50
    |
-LL | #[error(code = "E0456", code = "E0457", slug = "bar")]
-   |                ^^^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
+   |                                                  ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:113:46
+  --> $DIR/diagnostic-derive.rs:116:66
    |
-LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
-   |                                              ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
+   |                                                                  ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:113:32
+  --> $DIR/diagnostic-derive.rs:116:50
    |
-LL | #[error(code = "E0456", slug = "foo", slug = "bar")]
-   |                                ^^^^^
+LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
+   |                                                  ^^^^^^^
+
+error: `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:121:43
+   |
+LL | #[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic kind not specified
-  --> $DIR/diagnostic-derive.rs:118:1
+  --> $DIR/diagnostic-derive.rs:126:1
    |
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use the `#[error(...)]` attribute to create an error
 
-error: `slug` not specified
-  --> $DIR/diagnostic-derive.rs:121:1
+error: diagnostic slug not specified
+  --> $DIR/diagnostic-derive.rs:129:1
    |
 LL | / #[error(code = "E0456")]
+LL | |
 LL | | struct SlugNotProvided {}
    | |_________________________^
    |
-   = help: use the `#[error(slug = "...")]` attribute to set this diagnostic's slug
+   = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:131:5
+  --> $DIR/diagnostic-derive.rs:140:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: `#[nonsense]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:139:5
+  --> $DIR/diagnostic-derive.rs:148:5
    |
 LL |     #[nonsense]
    |     ^^^^^^^^^^^
    |
    = help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes
 
-error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:156:5
+error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
+  --> $DIR/diagnostic-derive.rs:165:5
    |
-LL |     #[label = "bar"]
-   |     ^^^^^^^^^^^^^^^^
+LL |     #[label(typeck::label)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:164:42
+  --> $DIR/diagnostic-derive.rs:173:45
    |
-LL |     #[suggestion(message = "bar", code = "{name}")]
-   |                                          ^^^^^^^^
+LL |     #[suggestion(typeck::suggestion, code = "{name}")]
+   |                                             ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/diagnostic-derive.rs:169:16
+  --> $DIR/diagnostic-derive.rs:178:16
    |
 LL | #[derive(SessionDiagnostic)]
    |           -    ^ expected `'}'` in format string
@@ -237,7 +271,7 @@ LL | #[derive(SessionDiagnostic)]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
-  --> $DIR/diagnostic-derive.rs:179:15
+  --> $DIR/diagnostic-derive.rs:188:15
    |
 LL | #[derive(SessionDiagnostic)]
    |               ^ unmatched `}` in format string
@@ -245,14 +279,14 @@ LL | #[derive(SessionDiagnostic)]
    = note: if you intended to print `}`, you can escape it using `}}`
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:199:5
+error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
+  --> $DIR/diagnostic-derive.rs:208:5
    |
-LL |     #[label = "bar"]
-   |     ^^^^^^^^^^^^^^^^
+LL |     #[label(typeck::label)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:224:18
+  --> $DIR/diagnostic-derive.rs:233:18
    |
 LL |     #[suggestion(nonsense = "bar")]
    |                  ^^^^^^^^^^^^^^^^
@@ -260,7 +294,7 @@ LL |     #[suggestion(nonsense = "bar")]
    = help: only `message`, `code` and `applicability` are valid field attributes
 
 error: `#[suggestion(msg = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:232:18
+  --> $DIR/diagnostic-derive.rs:241:18
    |
 LL |     #[suggestion(msg = "bar")]
    |                  ^^^^^^^^^^^
@@ -268,9 +302,9 @@ LL |     #[suggestion(msg = "bar")]
    = help: only `message`, `code` and `applicability` are valid field attributes
 
 error: wrong field type for suggestion
-  --> $DIR/diagnostic-derive.rs:254:5
+  --> $DIR/diagnostic-derive.rs:263:5
    |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
 LL | |     suggestion: Applicability,
    | |_____________________________^
@@ -278,55 +312,77 @@ LL | |     suggestion: Applicability,
    = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
-  --> $DIR/diagnostic-derive.rs:269:5
+  --> $DIR/diagnostic-derive.rs:278:5
    |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
 LL | |     suggestion: (Span, Span, Applicability),
    | |___________________________________________^
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/diagnostic-derive.rs:277:5
+  --> $DIR/diagnostic-derive.rs:286:5
    |
-LL | /     #[suggestion(message = "bar", code = "This is suggested code")]
+LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
 LL | |     suggestion: (Applicability, Applicability, Span),
    | |____________________________________________________^
 
-error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:285:5
-   |
-LL |     #[label("bar")]
-   |     ^^^^^^^^^^^^^^^
+error: `#[label = ...]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:294:5
    |
-   = help: only `suggestion{,_short,_hidden,_verbose}` are valid field attributes
+LL |     #[label = "bar"]
+   |     ^^^^^^^^^^^^^^^^
 
 error: applicability cannot be set in both the field and attribute
-  --> $DIR/diagnostic-derive.rs:436:49
+  --> $DIR/diagnostic-derive.rs:445:52
    |
-LL |     #[suggestion(message = "bar", code = "...", applicability = "maybe-incorrect")]
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/diagnostic-derive.rs:444:49
+  --> $DIR/diagnostic-derive.rs:453:52
+   |
+LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[label(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:516:5
+   |
+LL |     #[label(typeck::label, foo)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[label(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:524:5
+   |
+LL |     #[label(typeck::label, foo = "...")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#[label(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:532:5
    |
-LL |     #[suggestion(message = "bar", code = "...", applicability = "batman")]
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[label(typeck::label, foo("..."))]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
   --> $DIR/diagnostic-derive.rs:51:3
    |
-LL | #[nonsense(code = "E0123", slug = "foo")]
+LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:139:7
+  --> $DIR/diagnostic-derive.rs:148:7
    |
 LL |     #[nonsense]
    |       ^^^^^^^^
 
+error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent`
+  --> $DIR/diagnostic-derive.rs:64:9
+   |
+LL | #[error(nonsense, code = "E0123")]
+   |         ^^^^^^^^ not found in `rustc_errors::fluent`
+
 error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-  --> $DIR/diagnostic-derive.rs:329:10
+  --> $DIR/diagnostic-derive.rs:338:10
    |
 LL | #[derive(SessionDiagnostic)]
    |          ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
@@ -345,6 +401,7 @@ LL |         arg: impl IntoDiagnosticArg,
    |                   ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 39 previous errors
+error: aborting due to 46 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0425.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index bb406c35c0e..6f4b6105b3e 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -20,7 +20,7 @@ use rustc_span::Span;
 use rustc_macros::SessionSubdiagnostic;
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-a")]
+#[label(parser::add_paren)]
 struct A {
     #[primary_span]
     span: Span,
@@ -29,13 +29,13 @@ struct A {
 
 #[derive(SessionSubdiagnostic)]
 enum B {
-    #[label(slug = "label-b-a")]
+    #[label(parser::add_paren)]
     A {
         #[primary_span]
         span: Span,
         var: String,
     },
-    #[label(slug = "label-b-b")]
+    #[label(parser::add_paren)]
     B {
         #[primary_span]
         span: Span,
@@ -44,7 +44,7 @@ enum B {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-c")]
+#[label(parser::add_paren)]
 //~^ ERROR label without `#[primary_span]` field
 struct C {
     var: String,
@@ -116,7 +116,8 @@ struct K {
 
 #[derive(SessionSubdiagnostic)]
 #[label(slug)]
-//~^ ERROR `#[label(slug)]` is not a valid attribute
+//~^ ERROR cannot find value `slug` in module `rustc_errors::fluent`
+//~^^ NOTE not found in `rustc_errors::fluent`
 struct L {
     #[primary_span]
     span: Span,
@@ -125,7 +126,7 @@ struct L {
 
 #[derive(SessionSubdiagnostic)]
 #[label()]
-//~^ ERROR `slug` must be set in a `#[label(...)]` attribute
+//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
 struct M {
     #[primary_span]
     span: Span,
@@ -133,7 +134,7 @@ struct M {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(code = "...")]
+#[label(parser::add_paren, code = "...")]
 //~^ ERROR `code` is not a valid nested attribute of a `label` attribute
 struct N {
     #[primary_span]
@@ -142,11 +143,20 @@ struct N {
 }
 
 #[derive(SessionSubdiagnostic)]
+#[label(parser::add_paren, applicability = "machine-applicable")]
+//~^ ERROR `applicability` is not a valid nested attribute of a `label` attribute
+struct O {
+    #[primary_span]
+    span: Span,
+    var: String,
+}
+
+#[derive(SessionSubdiagnostic)]
 #[foo]
 //~^ ERROR cannot find attribute `foo` in this scope
 //~^^ ERROR unsupported type attribute for subdiagnostic enum
-enum O {
-    #[label(slug = "...")]
+enum P {
+    #[label(parser::add_paren)]
     A {
         #[primary_span]
         span: Span,
@@ -155,7 +165,7 @@ enum O {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum P {
+enum Q {
     #[bar]
 //~^ ERROR `#[bar]` is not a valid attribute
 //~^^ ERROR cannot find attribute `bar` in this scope
@@ -167,7 +177,7 @@ enum P {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum Q {
+enum R {
     #[bar = "..."]
 //~^ ERROR `#[bar = ...]` is not a valid attribute
 //~^^ ERROR cannot find attribute `bar` in this scope
@@ -179,7 +189,7 @@ enum Q {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum R {
+enum S {
     #[bar = 4]
 //~^ ERROR `#[bar = ...]` is not a valid attribute
 //~^^ ERROR cannot find attribute `bar` in this scope
@@ -191,7 +201,7 @@ enum R {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum S {
+enum T {
     #[bar("...")]
 //~^ ERROR `#[bar("...")]` is not a valid attribute
 //~^^ ERROR cannot find attribute `bar` in this scope
@@ -203,9 +213,9 @@ enum S {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum T {
+enum U {
     #[label(code = "...")]
-//~^ ERROR `code` is not a valid nested attribute of a `label`
+//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
     A {
         #[primary_span]
         span: Span,
@@ -214,8 +224,8 @@ enum T {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum U {
-    #[label(slug = "label-u")]
+enum V {
+    #[label(parser::add_paren)]
     A {
         #[primary_span]
         span: Span,
@@ -230,17 +240,17 @@ enum U {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
+#[label(parser::add_paren)]
 //~^ ERROR label without `#[primary_span]` field
-struct V {
+struct W {
     #[primary_span]
     //~^ ERROR the `#[primary_span]` attribute can only be applied to fields of type `Span`
     span: String,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
-struct W {
+#[label(parser::add_paren)]
+struct X {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -249,8 +259,8 @@ struct W {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
-struct X {
+#[label(parser::add_paren)]
+struct Y {
     #[primary_span]
     span: Span,
     #[bar]
@@ -260,8 +270,8 @@ struct X {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
-struct Y {
+#[label(parser::add_paren)]
+struct Z {
     #[primary_span]
     span: Span,
     #[bar = "..."]
@@ -271,8 +281,8 @@ struct Y {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "...")]
-struct Z {
+#[label(parser::add_paren)]
+struct AA {
     #[primary_span]
     span: Span,
     #[bar("...")]
@@ -282,8 +292,8 @@ struct Z {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-aa")]
-struct AA {
+#[label(parser::add_paren)]
+struct AB {
     #[primary_span]
     span: Span,
     #[skip_arg]
@@ -291,36 +301,35 @@ struct AA {
 }
 
 #[derive(SessionSubdiagnostic)]
-union AB {
+union AC {
 //~^ ERROR unexpected unsupported untagged union
     span: u32,
     b: u64
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-ac-1")]
+#[label(parser::add_paren)]
 //~^ NOTE previously specified here
 //~^^ NOTE previously specified here
-#[label(slug = "label-ac-2")]
+#[label(parser::add_paren)]
 //~^ ERROR specified multiple times
 //~^^ ERROR specified multiple times
-struct AC {
+struct AD {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-ad-1", slug = "label-ad-2")]
-//~^ ERROR specified multiple times
-//~^^ NOTE previously specified here
-struct AD {
+#[label(parser::add_paren, parser::add_paren)]
+//~^ ERROR `#[label(parser::add_paren)]` is not a valid attribute
+struct AE {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[label(slug = "label-ad-1")]
-struct AE {
+#[label(parser::add_paren)]
+struct AF {
     #[primary_span]
 //~^ NOTE previously specified here
     span_a: Span,
@@ -330,15 +339,15 @@ struct AE {
 }
 
 #[derive(SessionSubdiagnostic)]
-struct AF {
+struct AG {
 //~^ ERROR subdiagnostic kind not specified
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "suggestion-af", code = "...")]
-struct AG {
+#[suggestion(parser::add_paren, code = "...")]
+struct AH {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -347,8 +356,8 @@ struct AG {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum AH {
-    #[suggestion(slug = "suggestion-ag-a", code = "...")]
+enum AI {
+    #[suggestion(parser::add_paren, code = "...")]
     A {
         #[primary_span]
         span: Span,
@@ -356,7 +365,7 @@ enum AH {
         applicability: Applicability,
         var: String,
     },
-    #[suggestion(slug = "suggestion-ag-b", code = "...")]
+    #[suggestion(parser::add_paren, code = "...")]
     B {
         #[primary_span]
         span: Span,
@@ -367,10 +376,10 @@ enum AH {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...", code = "...")]
+#[suggestion(parser::add_paren, code = "...", code = "...")]
 //~^ ERROR specified multiple times
 //~^^ NOTE previously specified here
-struct AI {
+struct AJ {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -378,8 +387,8 @@ struct AI {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...")]
-struct AJ {
+#[suggestion(parser::add_paren, code = "...")]
+struct AK {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -391,9 +400,9 @@ struct AJ {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...")]
+#[suggestion(parser::add_paren, code = "...")]
 //~^ ERROR suggestion without `applicability`
-struct AK {
+struct AL {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -402,17 +411,17 @@ struct AK {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...")]
+#[suggestion(parser::add_paren, code = "...")]
 //~^ ERROR suggestion without `applicability`
-struct AL {
+struct AM {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...")]
+#[suggestion(parser::add_paren)]
 //~^ ERROR suggestion without `code = "..."`
-struct AM {
+struct AN {
     #[primary_span]
     span: Span,
     #[applicability]
@@ -420,34 +429,34 @@ struct AM {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code ="...", applicability = "foo")]
+#[suggestion(parser::add_paren, code ="...", applicability = "foo")]
 //~^ ERROR invalid applicability
-struct AN {
+struct AO {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[help(slug = "label-am")]
-struct AO {
+#[help(parser::add_paren)]
+struct AP {
     var: String
 }
 
 #[derive(SessionSubdiagnostic)]
-#[note(slug = "label-an")]
-struct AP;
+#[note(parser::add_paren)]
+struct AQ;
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code = "...")]
+#[suggestion(parser::add_paren, code = "...")]
 //~^ ERROR suggestion without `applicability`
 //~^^ ERROR suggestion without `#[primary_span]` field
-struct AQ {
+struct AR {
     var: String,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code ="...", applicability = "machine-applicable")]
-struct AR {
+#[suggestion(parser::add_paren, code ="...", applicability = "machine-applicable")]
+struct AS {
     #[primary_span]
     span: Span,
 }
@@ -455,8 +464,8 @@ struct AR {
 #[derive(SessionSubdiagnostic)]
 #[label]
 //~^ ERROR unsupported type attribute for subdiagnostic enum
-enum AS {
-    #[label(slug = "...")]
+enum AT {
+    #[label(parser::add_paren)]
     A {
         #[primary_span]
         span: Span,
@@ -465,24 +474,24 @@ enum AS {
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
-struct AT {
+#[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+struct AU {
     #[primary_span]
     span: Span,
     var: String,
 }
 
 #[derive(SessionSubdiagnostic)]
-#[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+#[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
 //~^ ERROR `var` doesn't refer to a field on this type
-struct AU {
+struct AV {
     #[primary_span]
     span: Span,
 }
 
 #[derive(SessionSubdiagnostic)]
-enum AV {
-    #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+enum AW {
+    #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
     A {
         #[primary_span]
         span: Span,
@@ -491,8 +500,8 @@ enum AV {
 }
 
 #[derive(SessionSubdiagnostic)]
-enum AW {
-    #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
+enum AX {
+    #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
 //~^ ERROR `var` doesn't refer to a field on this type
     A {
         #[primary_span]
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 4984cc4b318..f833bd210f7 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -1,7 +1,7 @@
 error: label without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:47:1
    |
-LL | / #[label(slug = "label-c")]
+LL | / #[label(parser::add_paren)]
 LL | |
 LL | | struct C {
 LL | |     var: String,
@@ -32,98 +32,106 @@ error: `#[label(bug = ...)]` is not a valid attribute
 LL | #[label(bug = "...")]
    |         ^^^^^^^^^^^
    |
-   = help: only `code`, `slug` and `applicability` are valid nested attributes
+   = help: first argument of the attribute should be the diagnostic slug
 
 error: `#[label("...")]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:91:9
    |
 LL | #[label("...")]
    |         ^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
 error: `#[label(slug = ...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:100:9
    |
 LL | #[label(slug = 4)]
    |         ^^^^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
 error: `#[label(slug(...))]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:109:9
    |
 LL | #[label(slug("..."))]
    |         ^^^^^^^^^^^
-
-error: `#[label(slug)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:118:9
    |
-LL | #[label(slug)]
-   |         ^^^^
+   = help: first argument of the attribute should be the diagnostic slug
 
-error: `slug` must be set in a `#[label(...)]` attribute
-  --> $DIR/subdiagnostic-derive.rs:127:1
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:128:1
    |
 LL | #[label()]
    | ^^^^^^^^^^
 
 error: `code` is not a valid nested attribute of a `label` attribute
-  --> $DIR/subdiagnostic-derive.rs:136:1
+  --> $DIR/subdiagnostic-derive.rs:137:1
+   |
+LL | #[label(parser::add_paren, code = "...")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `applicability` is not a valid nested attribute of a `label` attribute
+  --> $DIR/subdiagnostic-derive.rs:146:1
    |
-LL | #[label(code = "...")]
-   | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren, applicability = "machine-applicable")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:145:1
+  --> $DIR/subdiagnostic-derive.rs:155:1
    |
 LL | #[foo]
    | ^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:159:5
+  --> $DIR/subdiagnostic-derive.rs:169:5
    |
 LL |     #[bar]
    |     ^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:171:5
+  --> $DIR/subdiagnostic-derive.rs:181:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar = ...]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:183:5
+  --> $DIR/subdiagnostic-derive.rs:193:5
    |
 LL |     #[bar = 4]
    |     ^^^^^^^^^^
 
 error: `#[bar("...")]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:195:11
+  --> $DIR/subdiagnostic-derive.rs:205:11
    |
 LL |     #[bar("...")]
    |           ^^^^^
+   |
+   = help: first argument of the attribute should be the diagnostic slug
 
-error: `code` is not a valid nested attribute of a `label` attribute
-  --> $DIR/subdiagnostic-derive.rs:207:5
+error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+  --> $DIR/subdiagnostic-derive.rs:217:5
    |
 LL |     #[label(code = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:224:5
+  --> $DIR/subdiagnostic-derive.rs:234:5
    |
 LL |     B {
    |     ^
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
-  --> $DIR/subdiagnostic-derive.rs:236:5
+  --> $DIR/subdiagnostic-derive.rs:246:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: label without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:233:1
+  --> $DIR/subdiagnostic-derive.rs:243:1
    |
-LL | / #[label(slug = "...")]
+LL | / #[label(parser::add_paren)]
 LL | |
-LL | | struct V {
+LL | | struct W {
 LL | |     #[primary_span]
 LL | |
 LL | |     span: String,
@@ -131,13 +139,13 @@ LL | | }
    | |_^
 
 error: `#[applicability]` is only valid on suggestions
-  --> $DIR/subdiagnostic-derive.rs:246:5
+  --> $DIR/subdiagnostic-derive.rs:256:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: `#[bar]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:256:5
+  --> $DIR/subdiagnostic-derive.rs:266:5
    |
 LL |     #[bar]
    |     ^^^^^^
@@ -145,21 +153,21 @@ 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:267:5
+  --> $DIR/subdiagnostic-derive.rs:277:5
    |
 LL |     #[bar = "..."]
    |     ^^^^^^^^^^^^^^
 
 error: `#[bar(...)]` is not a valid attribute
-  --> $DIR/subdiagnostic-derive.rs:278:5
+  --> $DIR/subdiagnostic-derive.rs:288:5
    |
 LL |     #[bar("...")]
    |     ^^^^^^^^^^^^^
 
 error: unexpected unsupported untagged union
-  --> $DIR/subdiagnostic-derive.rs:294:1
+  --> $DIR/subdiagnostic-derive.rs:304:1
    |
-LL | / union AB {
+LL | / union AC {
 LL | |
 LL | |     span: u32,
 LL | |     b: u64
@@ -167,95 +175,91 @@ LL | | }
    | |_^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:304:9
+  --> $DIR/subdiagnostic-derive.rs:314:1
    |
-LL | #[label(slug = "label-ac-2")]
-   |         ^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:301:9
+  --> $DIR/subdiagnostic-derive.rs:311:1
    |
-LL | #[label(slug = "label-ac-1")]
-   |         ^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:304:1
+  --> $DIR/subdiagnostic-derive.rs:314:1
    |
-LL | #[label(slug = "label-ac-2")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:301:1
+  --> $DIR/subdiagnostic-derive.rs:311:1
    |
-LL | #[label(slug = "label-ac-1")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:313:30
+error: `#[label(parser::add_paren)]` is not a valid attribute
+  --> $DIR/subdiagnostic-derive.rs:323:28
    |
-LL | #[label(slug = "label-ad-1", slug = "label-ad-2")]
-   |                              ^^^^^^^^^^^^^^^^^^^
+LL | #[label(parser::add_paren, parser::add_paren)]
+   |                            ^^^^^^^^^^^^^^^^^
    |
-note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:313:9
-   |
-LL | #[label(slug = "label-ad-1", slug = "label-ad-2")]
-   |         ^^^^^^^^^^^^^^^^^^^
+   = help: a diagnostic slug must be the first argument to the attribute
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:327:5
+  --> $DIR/subdiagnostic-derive.rs:336:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:324:5
+  --> $DIR/subdiagnostic-derive.rs:333:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: subdiagnostic kind not specified
-  --> $DIR/subdiagnostic-derive.rs:333:8
+  --> $DIR/subdiagnostic-derive.rs:342:8
    |
-LL | struct AF {
+LL | struct AG {
    |        ^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:370:42
+  --> $DIR/subdiagnostic-derive.rs:379:47
    |
-LL | #[suggestion(slug = "...", code = "...", code = "...")]
-   |                                          ^^^^^^^^^^^^
+LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
+   |                                               ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:370:28
+  --> $DIR/subdiagnostic-derive.rs:379:33
    |
-LL | #[suggestion(slug = "...", code = "...", code = "...")]
-   |                            ^^^^^^^^^^^^
+LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
+   |                                 ^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/subdiagnostic-derive.rs:388:5
+  --> $DIR/subdiagnostic-derive.rs:397:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/subdiagnostic-derive.rs:385:5
+  --> $DIR/subdiagnostic-derive.rs:394:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
-  --> $DIR/subdiagnostic-derive.rs:399:5
+  --> $DIR/subdiagnostic-derive.rs:408:5
    |
 LL |     #[applicability]
    |     ^^^^^^^^^^^^^^^^
 
 error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:394:1
+  --> $DIR/subdiagnostic-derive.rs:403:1
    |
-LL | / #[suggestion(slug = "...", code = "...")]
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
-LL | | struct AK {
+LL | | struct AL {
 LL | |     #[primary_span]
 ...  |
 LL | |     applicability: Span,
@@ -263,22 +267,22 @@ LL | | }
    | |_^
 
 error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:405:1
+  --> $DIR/subdiagnostic-derive.rs:414:1
    |
-LL | / #[suggestion(slug = "...", code = "...")]
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
-LL | | struct AL {
+LL | | struct AM {
 LL | |     #[primary_span]
 LL | |     span: Span,
 LL | | }
    | |_^
 
 error: suggestion without `code = "..."`
-  --> $DIR/subdiagnostic-derive.rs:413:1
+  --> $DIR/subdiagnostic-derive.rs:422:1
    |
-LL | / #[suggestion(slug = "...")]
+LL | / #[suggestion(parser::add_paren)]
 LL | |
-LL | | struct AM {
+LL | | struct AN {
 LL | |     #[primary_span]
 ...  |
 LL | |     applicability: Applicability,
@@ -286,50 +290,50 @@ LL | | }
    | |_^
 
 error: invalid applicability
-  --> $DIR/subdiagnostic-derive.rs:423:41
+  --> $DIR/subdiagnostic-derive.rs:432:46
    |
-LL | #[suggestion(slug = "...", code ="...", applicability = "foo")]
-   |                                         ^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
+   |                                              ^^^^^^^^^^^^^^^^^^^^^
 
 error: suggestion without `applicability`
-  --> $DIR/subdiagnostic-derive.rs:441:1
+  --> $DIR/subdiagnostic-derive.rs:450:1
    |
-LL | / #[suggestion(slug = "...", code = "...")]
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
 LL | |
-LL | | struct AQ {
+LL | | struct AR {
 LL | |     var: String,
 LL | | }
    | |_^
 
 error: suggestion without `#[primary_span]` field
-  --> $DIR/subdiagnostic-derive.rs:441:1
+  --> $DIR/subdiagnostic-derive.rs:450:1
    |
-LL | / #[suggestion(slug = "...", code = "...")]
+LL | / #[suggestion(parser::add_paren, code = "...")]
 LL | |
 LL | |
-LL | | struct AQ {
+LL | | struct AR {
 LL | |     var: String,
 LL | | }
    | |_^
 
 error: unsupported type attribute for subdiagnostic enum
-  --> $DIR/subdiagnostic-derive.rs:456:1
+  --> $DIR/subdiagnostic-derive.rs:465:1
    |
 LL | #[label]
    | ^^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:476:34
+  --> $DIR/subdiagnostic-derive.rs:485:39
    |
-LL | #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
-   |                                  ^^^^^^^
+LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+   |                                       ^^^^^^^
 
 error: `var` doesn't refer to a field on this type
-  --> $DIR/subdiagnostic-derive.rs:495:38
+  --> $DIR/subdiagnostic-derive.rs:504:43
    |
-LL |     #[suggestion(slug = "...", code ="{var}", applicability = "machine-applicable")]
-   |                                      ^^^^^^^
+LL |     #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
+   |                                           ^^^^^^^
 
 error: cannot find attribute `foo` in this scope
   --> $DIR/subdiagnostic-derive.rs:63:3
@@ -338,52 +342,59 @@ LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `foo` in this scope
-  --> $DIR/subdiagnostic-derive.rs:145:3
+  --> $DIR/subdiagnostic-derive.rs:155:3
    |
 LL | #[foo]
    |   ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:159:7
+  --> $DIR/subdiagnostic-derive.rs:169:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:171:7
+  --> $DIR/subdiagnostic-derive.rs:181:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:183:7
+  --> $DIR/subdiagnostic-derive.rs:193:7
    |
 LL |     #[bar = 4]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:195:7
+  --> $DIR/subdiagnostic-derive.rs:205:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:256:7
+  --> $DIR/subdiagnostic-derive.rs:266:7
    |
 LL |     #[bar]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:267:7
+  --> $DIR/subdiagnostic-derive.rs:277:7
    |
 LL |     #[bar = "..."]
    |       ^^^
 
 error: cannot find attribute `bar` in this scope
-  --> $DIR/subdiagnostic-derive.rs:278:7
+  --> $DIR/subdiagnostic-derive.rs:288:7
    |
 LL |     #[bar("...")]
    |       ^^^
 
-error: aborting due to 51 previous errors
+error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
+  --> $DIR/subdiagnostic-derive.rs:118:9
+   |
+LL | #[label(slug)]
+   |         ^^^^ not found in `rustc_errors::fluent`
+
+error: aborting due to 52 previous errors
 
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/array-slice-vec/array_const_index-0.stderr b/src/test/ui/array-slice-vec/array_const_index-0.stderr
index 641705e1c68..b44251efdea 100644
--- a/src/test/ui/array-slice-vec/array_const_index-0.stderr
+++ b/src/test/ui/array-slice-vec/array_const_index-0.stderr
@@ -12,3 +12,16 @@ LL | const B: i32 = (&A)[1];
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/array_const_index-0.rs:2:16
+   |
+LL | const B: i32 = (&A)[1];
+   | ---------------^^^^^^^-
+   |                |
+   |                index out of bounds: the length is 0 but the index is 1
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/array-slice-vec/array_const_index-1.stderr b/src/test/ui/array-slice-vec/array_const_index-1.stderr
index 4d52d38af5e..8beebafb04c 100644
--- a/src/test/ui/array-slice-vec/array_const_index-1.stderr
+++ b/src/test/ui/array-slice-vec/array_const_index-1.stderr
@@ -12,3 +12,16 @@ LL | const B: i32 = A[1];
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/array_const_index-1.rs:2:16
+   |
+LL | const B: i32 = A[1];
+   | ---------------^^^^-
+   |                |
+   |                index out of bounds: the length is 0 but the index is 1
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr
index 7406b2ddee9..f04ea0b7477 100644
--- a/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr
+++ b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr
@@ -29,3 +29,28 @@ LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/defaults-not-assumed-fail.rs:8:19
+   |
+LL |     const B: u8 = Self::A + 1;
+   |     --------------^^^^^^^^^^^-
+   |                   |
+   |                   attempt to compute `u8::MAX + 1_u8`, which would overflow
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/defaults-not-assumed-fail.rs:34:5
+   |
+LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/src/test/ui/borrowck/issue-81899.stderr b/src/test/ui/borrowck/issue-81899.stderr
index 92ebd5a220d..e7345ff3f9a 100644
--- a/src/test/ui/borrowck/issue-81899.stderr
+++ b/src/test/ui/borrowck/issue-81899.stderr
@@ -27,3 +27,16 @@ LL | const _CONST: &[u8] = &f(&[], |_| {});
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/issue-81899.rs:4:23
+   |
+LL | const _CONST: &[u8] = &f(&[], |_| {});
+   | ----------------------^^^^^^^^^^^^^^^-
+   |                       |
+   |                       referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/borrowck/issue-88434-minimal-example.stderr b/src/test/ui/borrowck/issue-88434-minimal-example.stderr
index d46cd862e34..47d83c65355 100644
--- a/src/test/ui/borrowck/issue-88434-minimal-example.stderr
+++ b/src/test/ui/borrowck/issue-88434-minimal-example.stderr
@@ -27,3 +27,16 @@ LL | const _CONST: &() = &f(&|_| {});
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/issue-88434-minimal-example.rs:3:21
+   |
+LL | const _CONST: &() = &f(&|_| {});
+   | --------------------^^^^^^^^^^^-
+   |                     |
+   |                     referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
index e6b07aba74d..b08a7cfc7fe 100644
--- a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
+++ b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
@@ -27,3 +27,16 @@ LL | const _CONST: &[u8] = &f(&[], |_| {});
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/issue-88434-removal-index-should-be-less.rs:3:23
+   |
+LL | const _CONST: &[u8] = &f(&[], |_| {});
+   | ----------------------^^^^^^^^^^^^^^^-
+   |                       |
+   |                       referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/assert-type-intrinsics.stderr b/src/test/ui/consts/assert-type-intrinsics.stderr
index bb57ee82cc1..89f8f2ffc55 100644
--- a/src/test/ui/consts/assert-type-intrinsics.stderr
+++ b/src/test/ui/consts/assert-type-intrinsics.stderr
@@ -37,3 +37,45 @@ LL | |     };
 
 error: aborting due to 3 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/assert-type-intrinsics.rs:14:9
+   |
+LL | /     const _BAD1: () = unsafe {
+LL | |         MaybeUninit::<!>::uninit().assume_init();
+   | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
+LL | |     };
+   | |______-
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/assert-type-intrinsics.rs:17:9
+   |
+LL | /     const _BAD2: () = unsafe {
+LL | |         intrinsics::assert_uninit_valid::<bool>();
+   | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
+LL | |     };
+   | |______-
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/assert-type-intrinsics.rs:20:9
+   |
+LL | /     const _BAD3: () = unsafe {
+LL | |         intrinsics::assert_zero_valid::<&'static i32>();
+   | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
+LL | |     };
+   | |______-
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr
index 96cb904fa1b..cccf62a8ff6 100644
--- a/src/test/ui/consts/assoc_const_generic_impl.stderr
+++ b/src/test/ui/consts/assoc_const_generic_impl.stderr
@@ -22,3 +22,20 @@ LL |         let () = Self::I_AM_ZERO_SIZED;
 
 error: aborting due to previous error; 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/assoc_const_generic_impl.rs:11:34
+   |
+LL |     const I_AM_ZERO_SIZED: ()  = [()][std::mem::size_of::<Self>()];
+   |     -----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                  |
+   |                                  index out of bounds: the length is 1 but the index is 4
+   |
+note: the lint level is defined here
+  --> $DIR/assoc_const_generic_impl.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-err-early.stderr b/src/test/ui/consts/const-err-early.stderr
index 2b3d8817387..385e770eb4f 100644
--- a/src/test/ui/consts/const-err-early.stderr
+++ b/src/test/ui/consts/const-err-early.stderr
@@ -60,3 +60,88 @@ LL | pub const E: u8 = [5u8][1];
 
 error: aborting due to 5 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-early.rs:3:19
+   |
+LL | pub const A: i8 = -i8::MIN;
+   | ------------------^^^^^^^^-
+   |                   |
+   |                   attempt to negate `i8::MIN`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-early.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-early.rs:5:19
+   |
+LL | pub const B: u8 = 200u8 + 200u8;
+   | ------------------^^^^^^^^^^^^^-
+   |                   |
+   |                   attempt to compute `200_u8 + 200_u8`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-early.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-early.rs:7:19
+   |
+LL | pub const C: u8 = 200u8 * 4;
+   | ------------------^^^^^^^^^-
+   |                   |
+   |                   attempt to compute `200_u8 * 4_u8`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-early.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-early.rs:9:19
+   |
+LL | pub const D: u8 = 42u8 - (42u8 + 1);
+   | ------------------^^^^^^^^^^^^^^^^^-
+   |                   |
+   |                   attempt to compute `42_u8 - 43_u8`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-early.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-early.rs:11:19
+   |
+LL | pub const E: u8 = [5u8][1];
+   | ------------------^^^^^^^^-
+   |                   |
+   |                   index out of bounds: the length is 1 but the index is 1
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-early.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-err-multi.stderr b/src/test/ui/consts/const-err-multi.stderr
index c8172e83d10..a195459ff08 100644
--- a/src/test/ui/consts/const-err-multi.stderr
+++ b/src/test/ui/consts/const-err-multi.stderr
@@ -49,3 +49,71 @@ LL | pub const D: i8 = 50 - A;
 
 error: aborting due to 4 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-multi.rs:3:19
+   |
+LL | pub const A: i8 = -i8::MIN;
+   | ------------------^^^^^^^^-
+   |                   |
+   |                   attempt to negate `i8::MIN`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-multi.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-multi.rs:6:19
+   |
+LL | pub const B: i8 = A;
+   | ------------------^-
+   |                   |
+   |                   referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-multi.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-multi.rs:9:19
+   |
+LL | pub const C: u8 = A as u8;
+   | ------------------^-------
+   |                   |
+   |                   referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-multi.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-err-multi.rs:12:24
+   |
+LL | pub const D: i8 = 50 - A;
+   | -----------------------^-
+   |                        |
+   |                        referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/const-err-multi.rs:1:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-err.stderr b/src/test/ui/consts/const-err.stderr
index 0c963874a84..3b03e702dc4 100644
--- a/src/test/ui/consts/const-err.stderr
+++ b/src/test/ui/consts/const-err.stderr
@@ -29,3 +29,20 @@ LL |     black_box((FOO, FOO));
 error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const-err.rs:11:17
+   |
+LL | const FOO: u8 = [5u8][1];
+   | ----------------^^^^^^^^-
+   |                 |
+   |                 index out of bounds: the length is 1 but the index is 1
+   |
+note: the lint level is defined here
+  --> $DIR/const-err.rs:5:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
index 9dc40030a6f..f88bf445426 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
@@ -33,3 +33,36 @@ LL |     println!("{}", FOO);
 error: aborting due to previous error; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/conditional_array_execution.rs:7:19
+   |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+   | ------------------^^^^^---------------------------
+   |                   |
+   |                   attempt to compute `5_u32 - 6_u32`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/conditional_array_execution.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: erroneous constant used
+  --> $DIR/conditional_array_execution.rs:12:20
+   |
+LL |     println!("{}", FOO);
+   |                    ^^^ referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/conditional_array_execution.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-2.stderr
index 26728cf5415..1c74b978827 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-2.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-2.stderr
@@ -12,3 +12,20 @@ LL |         NEG_NEG_128 => println!("A"),
 
 error: aborting due to 2 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const-eval-overflow-2.rs:11:25
+   |
+LL | const NEG_NEG_128: i8 = -NEG_128;
+   | ------------------------^^^^^^^^-
+   |                         |
+   |                         attempt to negate `i8::MIN`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow-2.rs:4:36
+   |
+LL | #![allow(unused_imports, warnings, const_err)]
+   |                                    ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr
index 66e86c352d1..948ead521ea 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr
@@ -107,3 +107,153 @@ LL | |      );
 
 error: aborting due to 8 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2.rs:14:6
+   |
+LL | / const VALS_I8: (i8,) =
+LL | |     (
+LL | |      i8::MIN - 1,
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2.rs:21:6
+   |
+LL | / const VALS_I16: (i16,) =
+LL | |     (
+LL | |      i16::MIN - 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2.rs:28:6
+   |
+LL | / const VALS_I32: (i32,) =
+LL | |     (
+LL | |      i32::MIN - 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2.rs:35:6
+   |
+LL | / const VALS_I64: (i64,) =
+LL | |     (
+LL | |      i64::MIN - 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2.rs:42:6
+   |
+LL | / const VALS_U8: (u8,) =
+LL | |     (
+LL | |      u8::MIN - 1,
+   | |      ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2.rs:48:6
+   |
+LL | / const VALS_U16: (u16,) = (
+LL | |      u16::MIN - 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2.rs:54:6
+   |
+LL | / const VALS_U32: (u32,) = (
+LL | |      u32::MIN - 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2.rs:61:6
+   |
+LL | / const VALS_U64: (u64,) =
+LL | |     (
+LL | |      u64::MIN - 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr
index 3401ba47765..5db6a49a98b 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr
@@ -107,3 +107,153 @@ LL | |      );
 
 error: aborting due to 8 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2b.rs:14:6
+   |
+LL | / const VALS_I8: (i8,) =
+LL | |     (
+LL | |      i8::MAX + 1,
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2b.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2b.rs:21:6
+   |
+LL | / const VALS_I16: (i16,) =
+LL | |     (
+LL | |      i16::MAX + 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2b.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2b.rs:28:6
+   |
+LL | / const VALS_I32: (i32,) =
+LL | |     (
+LL | |      i32::MAX + 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2b.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2b.rs:35:6
+   |
+LL | / const VALS_I64: (i64,) =
+LL | |     (
+LL | |      i64::MAX + 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2b.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2b.rs:42:6
+   |
+LL | / const VALS_U8: (u8,) =
+LL | |     (
+LL | |      u8::MAX + 1,
+   | |      ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2b.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2b.rs:48:6
+   |
+LL | / const VALS_U16: (u16,) = (
+LL | |      u16::MAX + 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2b.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2b.rs:54:6
+   |
+LL | / const VALS_U32: (u32,) = (
+LL | |      u32::MAX + 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2b.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2b.rs:61:6
+   |
+LL | / const VALS_U64: (u64,) =
+LL | |     (
+LL | |      u64::MAX + 1,
+   | |      ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2b.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr
index 93c64090f0e..ec3f3c11059 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr
@@ -107,3 +107,153 @@ LL | |      );
 
 error: aborting due to 8 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2c.rs:14:6
+   |
+LL | / const VALS_I8: (i8,) =
+LL | |     (
+LL | |      i8::MIN * 2,
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2c.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2c.rs:21:6
+   |
+LL | / const VALS_I16: (i16,) =
+LL | |     (
+LL | |      i16::MIN * 2,
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2c.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2c.rs:28:6
+   |
+LL | / const VALS_I32: (i32,) =
+LL | |     (
+LL | |      i32::MIN * 2,
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2c.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2c.rs:35:6
+   |
+LL | / const VALS_I64: (i64,) =
+LL | |     (
+LL | |      i64::MIN * 2,
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2c.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2c.rs:42:6
+   |
+LL | / const VALS_U8: (u8,) =
+LL | |     (
+LL | |      u8::MAX * 2,
+   | |      ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2c.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2c.rs:48:6
+   |
+LL | / const VALS_U16: (u16,) = (
+LL | |      u16::MAX * 2,
+   | |      ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2c.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2c.rs:54:6
+   |
+LL | / const VALS_U32: (u32,) = (
+LL | |      u32::MAX * 2,
+   | |      ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2c.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-eval-overflow2c.rs:61:6
+   |
+LL | / const VALS_U64: (u64,) =
+LL | |     (
+LL | |      u64::MAX * 2,
+   | |      ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow
+LL | |      );
+   | |_______-
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-overflow2c.rs:8:9
+   |
+LL | #![deny(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
index b74d5a2722b..bbec2a830e6 100644
--- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
@@ -35,3 +35,31 @@ query stack during panic:
 #1 [optimized_mir] optimizing MIR for `main`
 #2 [collect_and_partition_mono_items] collect_and_partition_mono_items
 end of query stack
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const-eval-query-stack.rs:19:16
+   |
+LL | const X: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+note: the lint level is defined here
+  --> $DIR/const-eval-query-stack.rs:18:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/const-eval-query-stack.rs:23:27
+   |
+LL |     let x: &'static i32 = &X;
+   |                           ^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr
index c19f6342b5b..b004637fd83 100644
--- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr
+++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr
@@ -321,3 +321,354 @@ LL |     const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.charact
 error: aborting due to 29 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:26:49
+   |
+LL |     const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
+   |     --------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                                 |
+   |                                                 unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:30:43
+   |
+LL |     const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 };
+   |     --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                           |
+   |                                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:34:45
+   |
+LL |     const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 };
+   |     ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                             |
+   |                                             unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:38:45
+   |
+LL |     const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 };
+   |     ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                             |
+   |                                             unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:42:45
+   |
+LL |     const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
+   |     ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                             |
+   |                                             unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:49:43
+   |
+LL |     const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 };
+   |     --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                           |
+   |                                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:53:45
+   |
+LL |     const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 };
+   |     ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                             |
+   |                                             unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:57:45
+   |
+LL |     const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 };
+   |     ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                             |
+   |                                             unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:61:45
+   |
+LL |     const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
+   |     ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                             |
+   |                                             unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:68:45
+   |
+LL |     const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 };
+   |     ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                             |
+   |                                             unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:72:45
+   |
+LL |     const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
+   |     ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                             |
+   |                                             unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:76:47
+   |
+LL |     const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey };
+   |     ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                               |
+   |                                               unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:80:47
+   |
+LL |     const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character };
+   |     ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                               |
+   |                                               unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:84:39
+   |
+LL |     const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 };
+   |     ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                       |
+   |                                       unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:88:41
+   |
+LL |     const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 };
+   |     ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                         |
+   |                                         unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:92:41
+   |
+LL |     const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 };
+   |     ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                         |
+   |                                         unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:96:41
+   |
+LL |     const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
+   |     ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                         |
+   |                                         unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:100:43
+   |
+LL |     const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 };
+   |     --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                           |
+   |                                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:104:39
+   |
+LL |     const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 };
+   |     ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                       |
+   |                                       unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:108:41
+   |
+LL |     const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 };
+   |     ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                         |
+   |                                         unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:112:41
+   |
+LL |     const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 };
+   |     ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                         |
+   |                                         unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:116:41
+   |
+LL |     const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
+   |     ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                         |
+   |                                         unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:120:43
+   |
+LL |     const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 };
+   |     --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                           |
+   |                                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:124:41
+   |
+LL |     const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 };
+   |     ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                         |
+   |                                         unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:128:41
+   |
+LL |     const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
+   |     ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                         |
+   |                                         unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:132:43
+   |
+LL |     const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey };
+   |     --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                           |
+   |                                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-pointer-values-in-various-types.rs:136:43
+   |
+LL |     const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character };
+   |     --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                           |
+   |                                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
index c17166263ba..daf3d8927c1 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -21,3 +21,79 @@ LL |     x(y)
 error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_fn_ptr_fail2.rs:12:5
+   |
+LL |     x(y)
+   |     ^^^^
+   |     |
+   |     calling non-const function `double`
+   |     inside `bar` at $DIR/const_fn_ptr_fail2.rs:12:5
+   |     inside `Y` at $DIR/const_fn_ptr_fail2.rs:15:18
+...
+LL | const Y: usize = bar(X, 2); // FIXME: should fail to typeck someday
+   | ---------------------------
+   |
+note: the lint level is defined here
+  --> $DIR/const_fn_ptr_fail2.rs:4:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_fn_ptr_fail2.rs:12:5
+   |
+LL |     x(y)
+   |     ^^^^
+   |     |
+   |     calling non-const function `double`
+   |     inside `bar` at $DIR/const_fn_ptr_fail2.rs:12:5
+   |     inside `Z` at $DIR/const_fn_ptr_fail2.rs:16:18
+...
+LL | const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday
+   | --------------------------------
+   |
+note: the lint level is defined here
+  --> $DIR/const_fn_ptr_fail2.rs:4:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: erroneous constant used
+  --> $DIR/const_fn_ptr_fail2.rs:19:5
+   |
+LL |     assert_eq!(Y, 4);
+   |     ^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/const_fn_ptr_fail2.rs:4:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: erroneous constant used
+  --> $DIR/const_fn_ptr_fail2.rs:21:5
+   |
+LL |     assert_eq!(Z, 4);
+   |     ^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/const_fn_ptr_fail2.rs:4:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr
index 7e2a60929c7..9057b58ded9 100644
--- a/src/test/ui/consts/const-eval/erroneous-const.stderr
+++ b/src/test/ui/consts/const-eval/erroneous-const.stderr
@@ -41,3 +41,20 @@ LL | pub static FOO: () = no_codegen::<i32>();
 error: aborting due to previous error; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/erroneous-const.rs:6:22
+   |
+LL |     const VOID: () = [()][2];
+   |     -----------------^^^^^^^-
+   |                      |
+   |                      index out of bounds: the length is 1 but the index is 2
+   |
+note: the lint level is defined here
+  --> $DIR/erroneous-const.rs:2:9
+   |
+LL | #![warn(const_err, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/erroneous-const2.stderr b/src/test/ui/consts/const-eval/erroneous-const2.stderr
index 813d3ee249f..bf6cc8410a7 100644
--- a/src/test/ui/consts/const-eval/erroneous-const2.stderr
+++ b/src/test/ui/consts/const-eval/erroneous-const2.stderr
@@ -35,3 +35,20 @@ LL |         let _ = PrintName::<i32>::VOID;
 error: aborting due to previous error; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/erroneous-const2.rs:6:22
+   |
+LL |     const VOID: () = [()][2];
+   |     -----------------^^^^^^^-
+   |                      |
+   |                      index out of bounds: the length is 1 but the index is 2
+   |
+note: the lint level is defined here
+  --> $DIR/erroneous-const2.rs:2:9
+   |
+LL | #![warn(const_err, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/format.stderr b/src/test/ui/consts/const-eval/format.stderr
index 44f436ae4e3..b00cadcea99 100644
--- a/src/test/ui/consts/const-eval/format.stderr
+++ b/src/test/ui/consts/const-eval/format.stderr
@@ -76,3 +76,49 @@ LL |     println!("{:?}", 0);
 error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0015`.
+Future incompatibility report: Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/format.rs:2:12
+   |
+LL |     panic!("{:?}", 0);
+   |            ^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/format.rs:2:20
+   |
+LL |     panic!("{:?}", 0);
+   |                    ^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this error originates in the macro `$crate::const_format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/format.rs:11:14
+   |
+LL |     println!("{:?}", 0);
+   |              ^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/format.rs:11:22
+   |
+LL |     println!("{:?}", 0);
+   |                      ^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
index 73664fa49d1..7b3e46fccca 100644
--- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
@@ -22,3 +22,20 @@ LL |     let _ = PrintName::<T>::VOID;
 
 error: aborting due to previous error; 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/index-out-of-bounds-never-type.rs:10:61
+   |
+LL |     const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
+   |     --------------------------------------------------------^^^^^---
+   |                                                             |
+   |                                                             index out of bounds: the length is 0 but the index is 0
+   |
+note: the lint level is defined here
+  --> $DIR/index-out-of-bounds-never-type.rs:4:9
+   |
+LL | #![warn(const_err, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr
index 32ab7c74b89..53ed32638ce 100644
--- a/src/test/ui/consts/const-eval/issue-43197.stderr
+++ b/src/test/ui/consts/const-eval/issue-43197.stderr
@@ -60,3 +60,69 @@ LL |     println!("{} {}", X, Y);
 error: aborting due to 2 previous errors; 4 warnings emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/issue-43197.rs:10:20
+   |
+LL |     const X: u32 = 0 - 1;
+   |     ---------------^^^^^-
+   |                    |
+   |                    attempt to compute `0_u32 - 1_u32`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/issue-43197.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/issue-43197.rs:13:24
+   |
+LL |     const Y: u32 = foo(0 - 1);
+   |     -------------------^^^^^--
+   |                        |
+   |                        attempt to compute `0_u32 - 1_u32`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/issue-43197.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: erroneous constant used
+  --> $DIR/issue-43197.rs:16:23
+   |
+LL |     println!("{} {}", X, Y);
+   |                       ^ referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/issue-43197.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: erroneous constant used
+  --> $DIR/issue-43197.rs:16:26
+   |
+LL |     println!("{} {}", X, Y);
+   |                          ^ referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/issue-43197.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/src/test/ui/consts/const-eval/issue-44578.stderr b/src/test/ui/consts/const-eval/issue-44578.stderr
index bff9f40f82b..5ecdb7ef556 100644
--- a/src/test/ui/consts/const-eval/issue-44578.stderr
+++ b/src/test/ui/consts/const-eval/issue-44578.stderr
@@ -7,3 +7,36 @@ LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
 error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/issue-44578.rs:15:24
+   |
+LL |     const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
+   |     -------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                        |
+   |                        index out of bounds: the length is 1 but the index is 1
+   |
+note: the lint level is defined here
+  --> $DIR/issue-44578.rs:3:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: erroneous constant used
+  --> $DIR/issue-44578.rs:27:20
+   |
+LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+note: the lint level is defined here
+  --> $DIR/issue-44578.rs:3:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr
index 298f0a4a446..67af3b2b1d3 100644
--- a/src/test/ui/consts/const-eval/issue-50814-2.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr
@@ -25,3 +25,16 @@ LL |     println!("{:x}", foo::<()>() as *const usize as usize);
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/issue-50814-2.rs:14:24
+   |
+LL |     const BAR: usize = [5, 6, 7][T::BOO];
+   |     -------------------^^^^^^^^^^^^^^^^^-
+   |                        |
+   |                        index out of bounds: the length is 3 but the index is 42
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr
index 87bea28e763..b82bc9ca2f8 100644
--- a/src/test/ui/consts/const-eval/issue-50814.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814.stderr
@@ -25,3 +25,16 @@ LL |     foo(0);
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/issue-50814.rs:15:21
+   |
+LL |     const MAX: u8 = A::MAX + B::MAX;
+   |     ----------------^^^^^^^^^^^^^^^-
+   |                     |
+   |                     attempt to compute `u8::MAX + u8::MAX`, which would overflow
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr b/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr
index a18c7e78d95..1a7d3861420 100644
--- a/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr
+++ b/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr
@@ -18,3 +18,22 @@ LL | | };
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/partial_ptr_overwrite.rs:8:9
+   |
+LL | / const PARTIAL_OVERWRITE: () = {
+LL | |     let mut p = &42;
+LL | |     unsafe {
+LL | |         let ptr: *mut _ = &mut p;
+LL | |         *(ptr as *mut u8) = 123;
+   | |         ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at alloc4
+...  |
+LL | |     let x = *p;
+LL | | };
+   | |__-
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
index 5bfd4ef92a9..be845339dfe 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
@@ -85,3 +85,53 @@ LL | | };
 
 warning: 7 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/promoted_errors.rs:15:5
+   |
+LL |       0 - 1
+   |       ^^^^^
+   |       |
+   |       attempt to compute `0_u32 - 1_u32`, which would overflow
+   |       inside `overflow` at $DIR/promoted_errors.rs:15:5
+   |       inside `X` at $DIR/promoted_errors.rs:43:29
+...
+LL | / const X: () = {
+LL | |     let _x: &'static u32 = &overflow();
+LL | |
+LL | |
+...  |
+LL | |     let _x: &'static i32 = &oob();
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:11:9
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/promoted_errors.rs:43:28
+   |
+LL | / const X: () = {
+LL | |     let _x: &'static u32 = &overflow();
+   | |                            ^^^^^^^^^^^ referenced constant has errors
+LL | |
+LL | |
+...  |
+LL | |     let _x: &'static i32 = &oob();
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:11:9
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
index 0a8a8aef3cf..c91d52336c3 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
@@ -86,3 +86,54 @@ LL | | };
 
 warning: 7 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/promoted_errors.rs:21:5
+   |
+LL |       1 / 0
+   |       ^^^^^
+   |       |
+   |       attempt to divide `1_i32` by zero
+   |       inside `div_by_zero1` at $DIR/promoted_errors.rs:21:5
+   |       inside `X` at $DIR/promoted_errors.rs:46:29
+...
+LL | / const X: () = {
+LL | |     let _x: &'static u32 = &overflow();
+LL | |
+LL | |
+...  |
+LL | |     let _x: &'static i32 = &oob();
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:11:9
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/promoted_errors.rs:46:28
+   |
+LL | / const X: () = {
+LL | |     let _x: &'static u32 = &overflow();
+LL | |
+LL | |
+LL | |     let _x: &'static i32 = &div_by_zero1();
+   | |                            ^^^^^^^^^^^^^^^ referenced constant has errors
+...  |
+LL | |     let _x: &'static i32 = &oob();
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:11:9
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
index 5bfd4ef92a9..be845339dfe 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
@@ -85,3 +85,53 @@ LL | | };
 
 warning: 7 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/promoted_errors.rs:15:5
+   |
+LL |       0 - 1
+   |       ^^^^^
+   |       |
+   |       attempt to compute `0_u32 - 1_u32`, which would overflow
+   |       inside `overflow` at $DIR/promoted_errors.rs:15:5
+   |       inside `X` at $DIR/promoted_errors.rs:43:29
+...
+LL | / const X: () = {
+LL | |     let _x: &'static u32 = &overflow();
+LL | |
+LL | |
+...  |
+LL | |     let _x: &'static i32 = &oob();
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:11:9
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/promoted_errors.rs:43:28
+   |
+LL | / const X: () = {
+LL | |     let _x: &'static u32 = &overflow();
+   | |                            ^^^^^^^^^^^ referenced constant has errors
+LL | |
+LL | |
+...  |
+LL | |     let _x: &'static i32 = &oob();
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:11:9
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr
index dd47dca2b2e..56d66827626 100644
--- a/src/test/ui/consts/const-eval/pub_const_err.stderr
+++ b/src/test/ui/consts/const-eval/pub_const_err.stderr
@@ -16,3 +16,20 @@ LL | #![warn(const_err)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/pub_const_err.rs:6:20
+   |
+LL | pub const Z: u32 = 0 - 1;
+   | -------------------^^^^^-
+   |                    |
+   |                    attempt to compute `0_u32 - 1_u32`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/pub_const_err.rs:2:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
index 9f413fb8fd7..202ea781e97 100644
--- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
+++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
@@ -16,3 +16,20 @@ LL | #![warn(const_err)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/pub_const_err_bin.rs:4:20
+   |
+LL | pub const Z: u32 = 0 - 1;
+   | -------------------^^^^^-
+   |                    |
+   |                    attempt to compute `0_u32 - 1_u32`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/pub_const_err_bin.rs:2:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr
index 83ac6c90a43..a55fd8c156e 100644
--- a/src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ref_to_int_match.32bit.stderr
@@ -24,3 +24,16 @@ LL |         10..=BAR => {},
 
 error: aborting due to 3 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ref_to_int_match.rs:25:27
+   |
+LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
+   | --------------------------^^^^^^^^^^^^^^^^---
+   |                           |
+   |                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr
index 83ac6c90a43..a55fd8c156e 100644
--- a/src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ref_to_int_match.64bit.stderr
@@ -24,3 +24,16 @@ LL |         10..=BAR => {},
 
 error: aborting due to 3 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ref_to_int_match.rs:25:27
+   |
+LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
+   | --------------------------^^^^^^^^^^^^^^^^---
+   |                           |
+   |                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
index c6fa14d0534..2440cd2272c 100644
--- a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
@@ -125,3 +125,58 @@ LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe {
 error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:26:1
+   |
+LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:30:1
+   |
+LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:45:1
+   |
+LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:49:1
+   |
+LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:63:1
+   |
+LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
index 25be593ab83..e9b4023068e 100644
--- a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
@@ -125,3 +125,58 @@ LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe {
 error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:26:1
+   |
+LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:30:1
+   |
+LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:45:1
+   |
+LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:49:1
+   |
+LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-enum.rs:63:1
+   |
+LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
index 8a4f23c033e..10a0ccd552b 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
@@ -176,3 +176,66 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
 error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:31:1
+   |
+LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:35:39
+   |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+   | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                       |
+   |                                       unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:35:38
+   |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+   | -------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                      |
+   |                                      referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:41:86
+   |
+LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
+   | -------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^----
+   |                                                                                      |
+   |                                                                                      unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:41:85
+   |
+LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
+   | ------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^----
+   |                                                                                     |
+   |                                                                                     referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
index da1c6d1a07f..e9fcefe12c7 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
@@ -176,3 +176,66 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
 error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:31:1
+   |
+LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:35:39
+   |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+   | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                       |
+   |                                       unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:35:38
+   |
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+   | -------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                      |
+   |                                      referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:41:86
+   |
+LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
+   | -------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^----
+   |                                                                                      |
+   |                                                                                      unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-ref-ptr.rs:41:85
+   |
+LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
+   | ------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^----
+   |                                                                                     |
+   |                                                                                     referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
index a78cff11589..0c398f5bfd4 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
@@ -344,3 +344,86 @@ LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
 error: aborting due to 32 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:42:1
+   |
+LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:46:1
+   |
+LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:75:1
+   |
+LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:82:1
+   |
+LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:87:40
+   |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+   | ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                        |
+   |                                        referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:95:42
+   |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+   | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                          |
+   |                                          referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:100:42
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                          |
+   |                                          referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
index 69a61d9caed..bf53995d956 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
@@ -344,3 +344,86 @@ LL |     mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
 error: aborting due to 32 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:42:1
+   |
+LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:46:1
+   |
+LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:75:1
+   |
+LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:82:1
+   |
+LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:87:40
+   |
+LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
+   | ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                        |
+   |                                        referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:95:42
+   |
+LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
+   | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                          |
+   |                                          referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ub-wide-ptr.rs:100:42
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                          |
+   |                                          referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-eval/unused-broken-const.stderr b/src/test/ui/consts/const-eval/unused-broken-const.stderr
index 2ce60ec16a3..bfc076aa5e6 100644
--- a/src/test/ui/consts/const-eval/unused-broken-const.stderr
+++ b/src/test/ui/consts/const-eval/unused-broken-const.stderr
@@ -12,3 +12,16 @@ LL | const FOO: i32 = [][0];
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/unused-broken-const.rs:5:18
+   |
+LL | const FOO: i32 = [][0];
+   | -----------------^^^^^-
+   |                  |
+   |                  index out of bounds: the length is 0 but the index is 0
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-external-macro-const-err.stderr b/src/test/ui/consts/const-external-macro-const-err.stderr
index a66d79a1616..205ee92dfd7 100644
--- a/src/test/ui/consts/const-external-macro-const-err.stderr
+++ b/src/test/ui/consts/const-external-macro-const-err.stderr
@@ -11,3 +11,15 @@ LL |     static_assert!(2 + 2 == 5);
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-external-macro-const-err.rs:12:5
+   |
+LL |     static_assert!(2 + 2 == 5);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this error originates in the macro `static_assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/src/test/ui/consts/const-float-bits-reject-conv.stderr b/src/test/ui/consts/const-float-bits-reject-conv.stderr
index f3fd098e848..d822171df72 100644
--- a/src/test/ui/consts/const-float-bits-reject-conv.stderr
+++ b/src/test/ui/consts/const-float-bits-reject-conv.stderr
@@ -214,3 +214,115 @@ LL |         const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
 error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-float-bits-reject-conv.rs:30:34
+   |
+LL |             const _: () = assert!($a);
+   |             --------------------------
+...
+LL |     const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
+   |                                  ^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-float-bits-reject-conv.rs:33:34
+   |
+LL |             const _: () = assert!($a);
+   |             --------------------------
+...
+LL |     const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
+   |                                  ^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-float-bits-reject-conv.rs:41:38
+   |
+LL |             const _: () = assert!($a == $b);
+   |             --------------------------------
+...
+LL |         const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
+   |                                      ^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-float-bits-reject-conv.rs:44:38
+   |
+LL |             const _: () = assert!($a == $b);
+   |             --------------------------------
+...
+LL |         const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
+   |                                      ^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-float-bits-reject-conv.rs:57:34
+   |
+LL |             const _: () = assert!($a);
+   |             --------------------------
+...
+LL |     const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
+   |                                  ^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-float-bits-reject-conv.rs:60:34
+   |
+LL |             const _: () = assert!($a);
+   |             --------------------------
+...
+LL |     const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
+   |                                  ^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-float-bits-reject-conv.rs:66:38
+   |
+LL |             const _: () = assert!($a == $b);
+   |             --------------------------------
+...
+LL |         const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
+   |                                      ^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-float-bits-reject-conv.rs:69:38
+   |
+LL |             const _: () = assert!($a == $b);
+   |             --------------------------------
+...
+LL |         const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
+   |                                      ^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-len-underflow-separate-spans.stderr b/src/test/ui/consts/const-len-underflow-separate-spans.stderr
index 70f645a6c40..0c10783476a 100644
--- a/src/test/ui/consts/const-len-underflow-separate-spans.stderr
+++ b/src/test/ui/consts/const-len-underflow-separate-spans.stderr
@@ -19,3 +19,16 @@ LL |     let a: [i8; LEN] = unimplemented!();
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-len-underflow-separate-spans.rs:7:20
+   |
+LL | const LEN: usize = ONE - TWO;
+   | -------------------^^^^^^^^^-
+   |                    |
+   |                    attempt to compute `1_usize - 2_usize`, which would overflow
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-prop-read-static-in-const.stderr b/src/test/ui/consts/const-prop-read-static-in-const.stderr
index 94d3f1c6145..a60cd16f05a 100644
--- a/src/test/ui/consts/const-prop-read-static-in-const.stderr
+++ b/src/test/ui/consts/const-prop-read-static-in-const.stderr
@@ -20,3 +20,16 @@ LL | const TEST: u8 = MY_STATIC;
 
 error: aborting due to previous error; 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-prop-read-static-in-const.rs:5:18
+   |
+LL | const TEST: u8 = MY_STATIC;
+   | -----------------^^^^^^^^^-
+   |                  |
+   |                  constant accesses static
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
index a9211c17a6b..c6e0b321124 100644
--- a/src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
+++ b/src/test/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
@@ -23,3 +23,29 @@ LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const
 
 error: aborting due to 2 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:31
+   |
+LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) };
+   | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                               |
+   |                               `extern type` does not have known layout
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:13:32
+   |
+LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) };
+   | -------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                                |
+   |                                `extern type` does not have known layout
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const-slice-oob.stderr b/src/test/ui/consts/const-slice-oob.stderr
index 6d2c79034d3..c9f949727bc 100644
--- a/src/test/ui/consts/const-slice-oob.stderr
+++ b/src/test/ui/consts/const-slice-oob.stderr
@@ -12,3 +12,16 @@ LL | const BAR: u32 = FOO[5];
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const-slice-oob.rs:4:18
+   |
+LL | const BAR: u32 = FOO[5];
+   | -----------------^^^^^^-
+   |                  |
+   |                  index out of bounds: the length is 3 but the index is 5
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr
index 5e706a4466e..ee95b0d5180 100644
--- a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr
+++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr
@@ -17,3 +17,21 @@ LL | | };
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/const_eval_limit_reached.rs:6:11
+   |
+LL | / const X: usize = {
+LL | |     let mut x = 0;
+LL | |     while x != 1000 {
+   | |           ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
+LL | |
+...  |
+LL | |     x
+LL | | };
+   | |__-
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/invalid-union.32bit.stderr b/src/test/ui/consts/invalid-union.32bit.stderr
index 38c38d1ae67..bd7c95342f7 100644
--- a/src/test/ui/consts/invalid-union.32bit.stderr
+++ b/src/test/ui/consts/invalid-union.32bit.stderr
@@ -22,3 +22,14 @@ LL |     let _: &'static _ = &C;
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/invalid-union.rs:41:25
+   |
+LL |     let _: &'static _ = &C;
+   |                         ^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/invalid-union.64bit.stderr b/src/test/ui/consts/invalid-union.64bit.stderr
index 6bfa97a2fde..0d8b8ffcc16 100644
--- a/src/test/ui/consts/invalid-union.64bit.stderr
+++ b/src/test/ui/consts/invalid-union.64bit.stderr
@@ -22,3 +22,14 @@ LL |     let _: &'static _ = &C;
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/invalid-union.rs:41:25
+   |
+LL |     let _: &'static _ = &C;
+   |                         ^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr
index 3b80b3486a8..73a0f8ec0d0 100644
--- a/src/test/ui/consts/issue-56164.stderr
+++ b/src/test/ui/consts/issue-56164.stderr
@@ -26,3 +26,14 @@ LL | const fn foo() { (||{})() }
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0015`.
+Future incompatibility report: Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/issue-56164.rs:1:18
+   |
+LL | const fn foo() { (||{})() }
+   |                  ^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/issue-66693.stderr b/src/test/ui/consts/issue-66693.stderr
index b8257684983..929f905ae91 100644
--- a/src/test/ui/consts/issue-66693.stderr
+++ b/src/test/ui/consts/issue-66693.stderr
@@ -34,3 +34,14 @@ LL |     panic!(&1);
 
 error: aborting due to 4 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/issue-66693.rs:11:12
+   |
+LL |     panic!(&1);
+   |            ^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/issue-miri-1910.stderr b/src/test/ui/consts/issue-miri-1910.stderr
index 87882449c73..e76a1f96b46 100644
--- a/src/test/ui/consts/issue-miri-1910.stderr
+++ b/src/test/ui/consts/issue-miri-1910.stderr
@@ -24,3 +24,28 @@ LL | | };
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+LL |           copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           |
+   |           unable to turn pointer into raw bytes
+   |           inside `std::ptr::read::<u8>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |           inside `ptr::const_ptr::<impl *const u8>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |           inside `C` at $DIR/issue-miri-1910.rs:7:5
+   |
+  ::: $DIR/issue-miri-1910.rs:4:1
+   |
+LL | / const C: () = unsafe {
+LL | |     let foo = Some(&42 as *const i32);
+LL | |     let one_and_a_half_pointers = std::mem::size_of::<*const i32>()/2*3;
+LL | |     (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read();
+LL | | };
+   | |__-
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/miri_unleashed/assoc_const.stderr b/src/test/ui/consts/miri_unleashed/assoc_const.stderr
index 193a49bb266..1765c9ed10a 100644
--- a/src/test/ui/consts/miri_unleashed/assoc_const.stderr
+++ b/src/test/ui/consts/miri_unleashed/assoc_const.stderr
@@ -15,3 +15,28 @@ LL |     const F: u32 = (U::X, 42).1;
 error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | calling non-const function `<Vec<u32> as Drop>::drop`
+   | inside `std::ptr::drop_in_place::<Vec<u32>> - shim(Some(Vec<u32>))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   | inside `std::ptr::drop_in_place::<(Vec<u32>, u32)> - shim(Some((Vec<u32>, u32)))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   | inside `<String as Bar<Vec<u32>, String>>::F` at $DIR/assoc_const.rs:14:31
+   |
+  ::: $DIR/assoc_const.rs:14:5
+   |
+LL |     const F: u32 = (U::X, 42).1;
+   |     ----------------------------
+   |
+note: the lint level is defined here
+  --> $DIR/assoc_const.rs:4:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr b/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr
index e15717979c5..f7be42de03f 100644
--- a/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr
+++ b/src/test/ui/consts/miri_unleashed/assoc_const_2.stderr
@@ -7,3 +7,20 @@ LL |     let y = <String as Bar<String>>::F;
 error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/assoc_const_2.rs:12:20
+   |
+LL |     const F: u32 = 100 / U::X;
+   |     ---------------^^^^^^^^^^-
+   |                    |
+   |                    attempt to divide `100_u32` by zero
+   |
+note: the lint level is defined here
+  --> $DIR/assoc_const_2.rs:3:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr
index c48f59fe848..98d4dff648a 100644
--- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr
+++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr
@@ -47,3 +47,58 @@ LL | const READ_MUT: u32 = unsafe { MUTABLE };
 error: aborting due to 3 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_refers_to_static.rs:13:5
+   |
+LL | / const MUTATE_INTERIOR_MUT: usize = {
+LL | |     static FOO: AtomicUsize = AtomicUsize::new(0);
+LL | |     FOO.fetch_add(1, Ordering::Relaxed)
+   | |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `AtomicUsize::fetch_add`
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/const_refers_to_static.rs:3:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_refers_to_static.rs:18:14
+   |
+LL | / const READ_INTERIOR_MUT: usize = {
+LL | |     static FOO: AtomicUsize = AtomicUsize::new(0);
+LL | |     unsafe { *(&FOO as *const _ as *const usize) }
+   | |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/const_refers_to_static.rs:3:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_refers_to_static.rs:22:32
+   |
+LL | const READ_MUT: u32 = unsafe { MUTABLE };
+   | -------------------------------^^^^^^^---
+   |                                |
+   |                                constant accesses static
+   |
+note: the lint level is defined here
+  --> $DIR/const_refers_to_static.rs:3:10
+   |
+LL | #![allow(const_err)]
+   |          ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
index 186c5b1856b..2a0766294d3 100644
--- a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
+++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
@@ -170,3 +170,45 @@ LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None =>
 error: aborting due to 10 previous errors; 3 warnings emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_refers_to_static_cross_crate.rs:25:15
+   |
+LL | / const U8_MUT2: &u8 = {
+LL | |     unsafe { &(*static_cross_crate::ZERO_REF)[0] }
+   | |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
+LL | |
+LL | |
+LL | |
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/const_refers_to_static_cross_crate.rs:23:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_refers_to_static_cross_crate.rs:32:20
+   |
+LL | / const U8_MUT3: &u8 = {
+LL | |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
+   | |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
+LL | |
+LL | |
+LL | |
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/const_refers_to_static_cross_crate.rs:30:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
index 7a64abd7b9c..2d4f038d914 100644
--- a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
+++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
@@ -170,3 +170,45 @@ LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None =>
 error: aborting due to 10 previous errors; 3 warnings emitted
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_refers_to_static_cross_crate.rs:25:15
+   |
+LL | / const U8_MUT2: &u8 = {
+LL | |     unsafe { &(*static_cross_crate::ZERO_REF)[0] }
+   | |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
+LL | |
+LL | |
+LL | |
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/const_refers_to_static_cross_crate.rs:23:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/const_refers_to_static_cross_crate.rs:32:20
+   |
+LL | / const U8_MUT3: &u8 = {
+LL | |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
+   | |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static
+LL | |
+LL | |
+LL | |
+LL | | };
+   | |__-
+   |
+note: the lint level is defined here
+  --> $DIR/const_refers_to_static_cross_crate.rs:30:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/ptr_comparisons.stderr b/src/test/ui/consts/ptr_comparisons.stderr
index 12f6ca0b51a..594576fe2cf 100644
--- a/src/test/ui/consts/ptr_comparisons.stderr
+++ b/src/test/ui/consts/ptr_comparisons.stderr
@@ -44,3 +44,29 @@ LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4
 error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ptr_comparisons.rs:65:27
+   |
+LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
+   | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |                           |
+   |                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/ptr_comparisons.rs:70:27
+   |
+LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
+   | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------
+   |                           |
+   |                           unable to turn pointer into raw bytes
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/recursive.stderr b/src/test/ui/consts/recursive.stderr
index 31ac1fff4e8..8d1e10d4176 100644
--- a/src/test/ui/consts/recursive.stderr
+++ b/src/test/ui/consts/recursive.stderr
@@ -29,3 +29,22 @@ LL | const X: () = f(1);
 
 error: aborting due to previous error; 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/recursive.rs:4:5
+   |
+LL |     f(x);
+   |     ^^^^
+   |     |
+   |     reached the configured maximum number of stack frames
+   |     inside `f::<i32>` at $DIR/recursive.rs:4:5
+   |     [... 126 additional calls inside `f::<i32>` at $DIR/recursive.rs:4:5 ...]
+   |     inside `X` at $DIR/recursive.rs:9:15
+...
+LL | const X: () = f(1);
+   | -------------------
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr
index e98eefc11c3..17dd6131436 100644
--- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr
+++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr
@@ -150,3 +150,147 @@ LL |     dbg!(i32::CONSTANT);
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/uninhabited-const-issue-61744.rs:4:5
+   |
+LL |     hint_unreachable()
+   |     ^^^^^^^^^^^^^^^^^^
+   |     |
+   |     reached the configured maximum number of stack frames
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:9:5
+   |     inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5
+   |     inside `<i32 as Const>::CONSTANT` at $DIR/uninhabited-const-issue-61744.rs:13:36
+...
+LL |     const CONSTANT: i32 = unsafe { fake_type() };
+   |     ---------------------------------------------
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/generic-associated-types/issue-91883.rs b/src/test/ui/generic-associated-types/issue-91883.rs
new file mode 100644
index 00000000000..3d4585a44df
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-91883.rs
@@ -0,0 +1,42 @@
+#![feature(generic_associated_types)]
+
+use std::fmt::Debug;
+use std::marker::PhantomData;
+
+#[derive(Debug)]
+pub struct TransactionImpl<'db> {
+    _marker: PhantomData<&'db ()>,
+}
+
+#[derive(Debug)]
+pub struct CursorImpl<'txn> {
+    _marker: PhantomData<&'txn ()>,
+}
+
+pub trait Cursor<'txn> {}
+
+pub trait Transaction<'db>: Send + Sync + Debug + Sized {
+    type Cursor<'tx>: Cursor<'tx>
+    where
+        'db: 'tx,
+        Self: 'tx;
+
+    fn cursor<'tx>(&'tx self) -> Result<Self::Cursor<'tx>, ()>
+    where
+        'db: 'tx;
+}
+
+impl<'tx> Cursor<'tx> for CursorImpl<'tx> {}
+
+impl<'db> Transaction<'db> for TransactionImpl<'db> {
+    type Cursor<'tx> = CursorImpl<'tx>; //~ ERROR lifetime bound not satisfied
+
+    fn cursor<'tx>(&'tx self) -> Result<Self::Cursor<'tx>, ()>
+    where
+        'db: 'tx,
+    {
+        loop {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-91883.stderr b/src/test/ui/generic-associated-types/issue-91883.stderr
new file mode 100644
index 00000000000..ed700876e02
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-91883.stderr
@@ -0,0 +1,26 @@
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/issue-91883.rs:32:24
+   |
+LL | /     type Cursor<'tx>: Cursor<'tx>
+LL | |     where
+LL | |         'db: 'tx,
+LL | |         Self: 'tx;
+   | |__________________- definition of `Cursor` from trait
+...
+LL |       type Cursor<'tx> = CursorImpl<'tx>;
+   |                          ^^^^^^^^^^^^^^^- help: try copying these clauses from the trait: `where 'db: 'tx, Self: 'tx`
+   |
+note: lifetime parameter instantiated with the lifetime `'db` as defined here
+  --> $DIR/issue-91883.rs:31:6
+   |
+LL | impl<'db> Transaction<'db> for TransactionImpl<'db> {
+   |      ^^^
+note: but lifetime parameter must outlive the lifetime `'tx` as defined here
+  --> $DIR/issue-91883.rs:32:17
+   |
+LL |     type Cursor<'tx> = CursorImpl<'tx>;
+   |                 ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0478`.
diff --git a/src/test/ui/limits/issue-55878.stderr b/src/test/ui/limits/issue-55878.stderr
index 90411353f08..1402d138703 100644
--- a/src/test/ui/limits/issue-55878.stderr
+++ b/src/test/ui/limits/issue-55878.stderr
@@ -23,3 +23,15 @@ LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: erroneous constant used
+  --> $DIR/issue-55878.rs:7:26
+   |
+LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+   = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr
index af6308f0d1b..c14529a7d09 100644
--- a/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.stderr
@@ -12,3 +12,16 @@ LL | const C: i32 = 1 / 0;
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/allowed-cli-deny-by-default-lint.rs:6:16
+   |
+LL | const C: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+   = note: requested on the command line with `--force-warn const-err`
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr
index 05656afd22d..dd71a168960 100644
--- a/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/allowed-deny-by-default-lint.stderr
@@ -12,3 +12,16 @@ LL | const C: i32 = 1 / 0;
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/allowed-deny-by-default-lint.rs:7:16
+   |
+LL | const C: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+   = note: requested on the command line with `--force-warn const-err`
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/lint/force-warn/deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/deny-by-default-lint.stderr
index ef295f99e64..d4e80584669 100644
--- a/src/test/ui/lint/force-warn/deny-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/deny-by-default-lint.stderr
@@ -12,3 +12,16 @@ LL | const C: i32 = 1 / 0;
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: any use of this value will cause an error
+  --> $DIR/deny-by-default-lint.rs:5:16
+   |
+LL | const C: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+   = note: requested on the command line with `--force-warn const-err`
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/mir/issue-92893.rs b/src/test/ui/mir/issue-92893.rs
index d2bbb4f1101..635050f376c 100644
--- a/src/test/ui/mir/issue-92893.rs
+++ b/src/test/ui/mir/issue-92893.rs
@@ -1,6 +1,7 @@
 struct Bug<A = [(); (let a = (), 1).1]> {
     //~^ `let` expressions are not supported here
-    //~^^ `let` expressions in this position are unstable [E0658]
+    //~| `let` expressions in this position are unstable [E0658]
+    //~| expected expression, found `let` statement
     a: A
 }
 
diff --git a/src/test/ui/mir/issue-92893.stderr b/src/test/ui/mir/issue-92893.stderr
index 063b5d66feb..4a0fcce31d7 100644
--- a/src/test/ui/mir/issue-92893.stderr
+++ b/src/test/ui/mir/issue-92893.stderr
@@ -1,3 +1,9 @@
+error: expected expression, found `let` statement
+  --> $DIR/issue-92893.rs:1:22
+   |
+LL | struct Bug<A = [(); (let a = (), 1).1]> {
+   |                      ^^^
+
 error: `let` expressions are not supported here
   --> $DIR/issue-92893.rs:1:22
    |
@@ -15,6 +21,6 @@ LL | struct Bug<A = [(); (let a = (), 1).1]> {
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
index 4a36515b991..bb1aff70d89 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
@@ -58,8 +58,10 @@ fn _macros() {
     }
     use_expr!((let 0 = 1 && 0 == 0));
     //~^ ERROR `let` expressions in this position are unstable
+    //~| ERROR expected expression, found `let` statement
     use_expr!((let 0 = 1));
     //~^ ERROR `let` expressions in this position are unstable
+    //~| ERROR expected expression, found `let` statement
     match () {
         #[cfg(FALSE)]
         () if let 0 = 1 => {}
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
index 8d93fb87f7a..370a57318fd 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
@@ -1,5 +1,17 @@
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:59:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:62:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^
+
 error: no rules expected the token `let`
-  --> $DIR/feature-gate.rs:69:15
+  --> $DIR/feature-gate.rs:71:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -58,7 +70,7 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:65:12
+  --> $DIR/feature-gate.rs:67:12
    |
 LL |         () if let 0 = 1 => {}
    |            ^^^^^^^^^^^^
@@ -203,7 +215,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:61:16
+  --> $DIR/feature-gate.rs:62:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
@@ -211,6 +223,6 @@ LL |     use_expr!((let 0 = 1));
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
-error: aborting due to 23 previous errors
+error: aborting due to 25 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
index 1bd8b74240e..36b730505c2 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -81,9 +81,11 @@ fn _macros() {
     use_expr!((let 0 = 1 && 0 == 0));
     //~^ ERROR `let` expressions are not supported here
     //~| ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
     use_expr!((let 0 = 1));
     //~^ ERROR `let` expressions are not supported here
     //~| ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 }
 
 fn nested_within_if_expr() {
@@ -147,7 +149,8 @@ fn nested_within_if_expr() {
     //~| ERROR mismatched types
     //~| ERROR mismatched types
 
-    if let true = let true = true {} //~ ERROR `let` expressions are not supported here
+    if let true = let true = true {}
+    //~^ ERROR `let` expressions are not supported here
 }
 
 fn nested_within_while_expr() {
@@ -211,7 +214,8 @@ fn nested_within_while_expr() {
     //~| ERROR mismatched types
     //~| ERROR mismatched types
 
-    while let true = let true = true {} //~ ERROR `let` expressions are not supported here
+    while let true = let true = true {}
+    //~^ ERROR `let` expressions are not supported here
 }
 
 fn not_error_because_clarified_intent() {
@@ -225,45 +229,85 @@ fn not_error_because_clarified_intent() {
 }
 
 fn outside_if_and_while_expr() {
-    &let 0 = 0; //~ ERROR `let` expressions are not supported here
+    &let 0 = 0;
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 
-    !let 0 = 0; //~ ERROR `let` expressions are not supported here
-    *let 0 = 0; //~ ERROR `let` expressions are not supported here
-    //~^ ERROR type `bool` cannot be dereferenced
-    -let 0 = 0; //~ ERROR `let` expressions are not supported here
-    //~^ ERROR cannot apply unary operator `-` to type `bool`
+    !let 0 = 0;
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
+    *let 0 = 0;
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR type `bool` cannot be dereferenced
+    //~| ERROR expected expression, found `let` statement
+    -let 0 = 0;
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR cannot apply unary operator `-` to type `bool`
+    //~| ERROR expected expression, found `let` statement
 
     fn _check_try_binds_tighter() -> Result<(), ()> {
         let 0 = 0?;
         //~^ ERROR the `?` operator can only be applied to values that implement `Try`
         Ok(())
     }
-    (let 0 = 0)?; //~ ERROR `let` expressions are not supported here
-    //~^ ERROR the `?` operator can only be used in a function that returns `Result`
+    (let 0 = 0)?;
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR the `?` operator can only be used in a function that returns `Result`
     //~| ERROR the `?` operator can only be applied to values that implement `Try`
+    //~| ERROR expected expression, found `let` statement
 
-    true || let 0 = 0; //~ ERROR `let` expressions are not supported here
-    (true || let 0 = 0); //~ ERROR `let` expressions are not supported here
-    true && (true || let 0 = 0); //~ ERROR `let` expressions are not supported here
+    true || let 0 = 0;
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
+    (true || let 0 = 0);
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
+    true && (true || let 0 = 0);
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 
     let mut x = true;
-    x = let 0 = 0; //~ ERROR `let` expressions are not supported here
+    x = let 0 = 0;
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 
-    true..(let 0 = 0); //~ ERROR `let` expressions are not supported here
-    ..(let 0 = 0); //~ ERROR `let` expressions are not supported here
-    (let 0 = 0)..; //~ ERROR `let` expressions are not supported here
+    true..(let 0 = 0);
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
+    ..(let 0 = 0);
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
+    (let 0 = 0)..;
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 
     (let Range { start: _, end: _ } = true..true || false);
     //~^ ERROR `let` expressions are not supported here
     //~| ERROR mismatched types
+    //~| ERROR expected expression, found `let` statement
 
     (let true = let true = true);
     //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
+
+    {
+        #[cfg(FALSE)]
+        let x = true && let y = 1;
+        //~^ ERROR expected expression, found `let` statement
+    }
+
+    #[cfg(FALSE)]
+    {
+        [1, 2, 3][let _ = ()]
+        //~^ ERROR expected expression, found `let` statement
+    }
 
     // Check function tail position.
     &let 0 = 0
     //~^ ERROR `let` expressions are not supported here
     //~| ERROR mismatched types
+    //~| ERROR expected expression, found `let` statement
 }
 
 // Let's make sure that `let` inside const generic arguments are considered.
@@ -335,4 +379,14 @@ fn with_parenthesis() {
     let fun = || true;
     if let true = (true && fun()) && (true) {
     }
+
+    #[cfg(FALSE)]
+    let x = (true && let y = 1);
+    //~^ ERROR expected expression, found `let` statement
+
+    #[cfg(FALSE)]
+    {
+        ([1, 2, 3][let _ = ()])
+        //~^ ERROR expected expression, found `let` statement
+    }
 }
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index f7f39bd0b9a..5cf06cf4b27 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -1,5 +1,113 @@
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:232:6
+   |
+LL |     &let 0 = 0;
+   |      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:236:6
+   |
+LL |     !let 0 = 0;
+   |      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:239:6
+   |
+LL |     *let 0 = 0;
+   |      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:243:6
+   |
+LL |     -let 0 = 0;
+   |      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:253:6
+   |
+LL |     (let 0 = 0)?;
+   |      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:259:13
+   |
+LL |     true || let 0 = 0;
+   |             ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:262:14
+   |
+LL |     (true || let 0 = 0);
+   |              ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:265:22
+   |
+LL |     true && (true || let 0 = 0);
+   |                      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:270:9
+   |
+LL |     x = let 0 = 0;
+   |         ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:274:12
+   |
+LL |     true..(let 0 = 0);
+   |            ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:277:8
+   |
+LL |     ..(let 0 = 0);
+   |        ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:280:6
+   |
+LL |     (let 0 = 0)..;
+   |      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:284:6
+   |
+LL |     (let Range { start: _, end: _ } = true..true || false);
+   |      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:289:6
+   |
+LL |     (let true = let true = true);
+   |      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:289:17
+   |
+LL |     (let true = let true = true);
+   |                 ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:296:25
+   |
+LL |         let x = true && let y = 1;
+   |                         ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:302:19
+   |
+LL |         [1, 2, 3][let _ = ()]
+   |                   ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:307:6
+   |
+LL |     &let 0 = 0
+   |      ^^^
+
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:293:9
+  --> $DIR/disallowed-positions.rs:337:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -9,6 +117,30 @@ help: enclose the `const` expression in braces
 LL |         { true && let 1 = 1 }
    |         +                   +
 
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:384:22
+   |
+LL |     let x = (true && let y = 1);
+   |                      ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:389:20
+   |
+LL |         ([1, 2, 3][let _ = ()])
+   |                    ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:81:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:85:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^
+
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:29:9
    |
@@ -270,33 +402,33 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:84:16
+  --> $DIR/disallowed-positions.rs:85:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:84:16
+  --> $DIR/disallowed-positions.rs:85:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:84:16
+  --> $DIR/disallowed-positions.rs:85:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:84:16
+  --> $DIR/disallowed-positions.rs:85:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:90:9
+  --> $DIR/disallowed-positions.rs:92:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -304,7 +436,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:93:9
+  --> $DIR/disallowed-positions.rs:95:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -312,7 +444,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:94:9
+  --> $DIR/disallowed-positions.rs:96:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -320,7 +452,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:96:9
+  --> $DIR/disallowed-positions.rs:98:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -328,72 +460,72 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:104:9
+  --> $DIR/disallowed-positions.rs:106:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:104:9
+  --> $DIR/disallowed-positions.rs:106:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:108:16
+  --> $DIR/disallowed-positions.rs:110:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:108:13
+  --> $DIR/disallowed-positions.rs:110:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:109:17
+  --> $DIR/disallowed-positions.rs:111:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:109:14
+  --> $DIR/disallowed-positions.rs:111:14
    |
 LL |     if (true || let 0 = 0) {}
    |              ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:110:25
+  --> $DIR/disallowed-positions.rs:112:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:110:22
+  --> $DIR/disallowed-positions.rs:112:22
    |
 LL |     if true && (true || let 0 = 0) {}
    |                      ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:111:25
+  --> $DIR/disallowed-positions.rs:113:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:111:17
+  --> $DIR/disallowed-positions.rs:113:17
    |
 LL |     if true || (true && let 0 = 0) {}
    |                 ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:114:12
+  --> $DIR/disallowed-positions.rs:116:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
@@ -401,46 +533,46 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:117:15
+  --> $DIR/disallowed-positions.rs:119:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:117:15
+  --> $DIR/disallowed-positions.rs:119:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:119:11
+  --> $DIR/disallowed-positions.rs:121:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:119:11
+  --> $DIR/disallowed-positions.rs:121:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:121:9
+  --> $DIR/disallowed-positions.rs:123:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:121:9
+  --> $DIR/disallowed-positions.rs:123:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:125:8
+  --> $DIR/disallowed-positions.rs:127:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -448,7 +580,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:129:8
+  --> $DIR/disallowed-positions.rs:131:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -456,7 +588,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:136:8
+  --> $DIR/disallowed-positions.rs:138:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -464,7 +596,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:144:8
+  --> $DIR/disallowed-positions.rs:146:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -472,7 +604,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:150:19
+  --> $DIR/disallowed-positions.rs:152:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
@@ -480,7 +612,7 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:154:12
+  --> $DIR/disallowed-positions.rs:157:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -488,7 +620,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:157:12
+  --> $DIR/disallowed-positions.rs:160:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -496,7 +628,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:158:12
+  --> $DIR/disallowed-positions.rs:161:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -504,7 +636,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:160:12
+  --> $DIR/disallowed-positions.rs:163:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -512,72 +644,72 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:168:12
+  --> $DIR/disallowed-positions.rs:171:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:168:12
+  --> $DIR/disallowed-positions.rs:171:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:172:19
+  --> $DIR/disallowed-positions.rs:175:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:172:16
+  --> $DIR/disallowed-positions.rs:175:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:173:20
+  --> $DIR/disallowed-positions.rs:176:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:173:17
+  --> $DIR/disallowed-positions.rs:176:17
    |
 LL |     while (true || let 0 = 0) {}
    |                 ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:174:28
+  --> $DIR/disallowed-positions.rs:177:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:174:25
+  --> $DIR/disallowed-positions.rs:177:25
    |
 LL |     while true && (true || let 0 = 0) {}
    |                         ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:175:28
+  --> $DIR/disallowed-positions.rs:178:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:175:20
+  --> $DIR/disallowed-positions.rs:178:20
    |
 LL |     while true || (true && let 0 = 0) {}
    |                    ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:178:15
+  --> $DIR/disallowed-positions.rs:181:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
@@ -585,46 +717,46 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:181:18
+  --> $DIR/disallowed-positions.rs:184:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:181:18
+  --> $DIR/disallowed-positions.rs:184:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:183:14
+  --> $DIR/disallowed-positions.rs:186:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:183:14
+  --> $DIR/disallowed-positions.rs:186:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:185:12
+  --> $DIR/disallowed-positions.rs:188:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:185:12
+  --> $DIR/disallowed-positions.rs:188:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:189:11
+  --> $DIR/disallowed-positions.rs:192:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -632,7 +764,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:193:11
+  --> $DIR/disallowed-positions.rs:196:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -640,7 +772,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:200:11
+  --> $DIR/disallowed-positions.rs:203:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -648,7 +780,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:208:11
+  --> $DIR/disallowed-positions.rs:211:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -656,7 +788,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:214:22
+  --> $DIR/disallowed-positions.rs:217:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
@@ -664,7 +796,7 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:228:6
+  --> $DIR/disallowed-positions.rs:232:6
    |
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
@@ -672,7 +804,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:230:6
+  --> $DIR/disallowed-positions.rs:236:6
    |
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
@@ -680,7 +812,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:231:6
+  --> $DIR/disallowed-positions.rs:239:6
    |
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
@@ -688,7 +820,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:233:6
+  --> $DIR/disallowed-positions.rs:243:6
    |
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
@@ -696,59 +828,59 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:241:6
+  --> $DIR/disallowed-positions.rs:253:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:241:6
+  --> $DIR/disallowed-positions.rs:253:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:245:13
+  --> $DIR/disallowed-positions.rs:259:13
    |
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:245:10
+  --> $DIR/disallowed-positions.rs:259:10
    |
 LL |     true || let 0 = 0;
    |          ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:246:14
+  --> $DIR/disallowed-positions.rs:262:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:246:11
+  --> $DIR/disallowed-positions.rs:262:11
    |
 LL |     (true || let 0 = 0);
    |           ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:247:22
+  --> $DIR/disallowed-positions.rs:265:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:247:19
+  --> $DIR/disallowed-positions.rs:265:19
    |
 LL |     true && (true || let 0 = 0);
    |                   ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:250:9
+  --> $DIR/disallowed-positions.rs:270:9
    |
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
@@ -756,46 +888,46 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:252:12
+  --> $DIR/disallowed-positions.rs:274:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:252:12
+  --> $DIR/disallowed-positions.rs:274:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:253:8
+  --> $DIR/disallowed-positions.rs:277:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:253:8
+  --> $DIR/disallowed-positions.rs:277:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:254:6
+  --> $DIR/disallowed-positions.rs:280:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:254:6
+  --> $DIR/disallowed-positions.rs:280:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:256:6
+  --> $DIR/disallowed-positions.rs:284:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -803,20 +935,20 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:260:6
+  --> $DIR/disallowed-positions.rs:289:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:260:6
+  --> $DIR/disallowed-positions.rs:289:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:264:6
+  --> $DIR/disallowed-positions.rs:307:6
    |
 LL |     &let 0 = 0
    |      ^^^^^^^^^
@@ -824,7 +956,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:275:17
+  --> $DIR/disallowed-positions.rs:319:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -832,7 +964,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:279:17
+  --> $DIR/disallowed-positions.rs:323:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -840,7 +972,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:283:17
+  --> $DIR/disallowed-positions.rs:327:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -848,7 +980,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:293:17
+  --> $DIR/disallowed-positions.rs:337:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -856,124 +988,124 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:302:9
+  --> $DIR/disallowed-positions.rs:346:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:302:9
+  --> $DIR/disallowed-positions.rs:346:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:306:9
+  --> $DIR/disallowed-positions.rs:350:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:306:9
+  --> $DIR/disallowed-positions.rs:350:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:309:9
+  --> $DIR/disallowed-positions.rs:353:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:309:9
+  --> $DIR/disallowed-positions.rs:353:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:309:32
+  --> $DIR/disallowed-positions.rs:353:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:309:32
+  --> $DIR/disallowed-positions.rs:353:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:316:9
+  --> $DIR/disallowed-positions.rs:360:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:316:9
+  --> $DIR/disallowed-positions.rs:360:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:316:31
+  --> $DIR/disallowed-positions.rs:360:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:316:31
+  --> $DIR/disallowed-positions.rs:360:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:320:9
+  --> $DIR/disallowed-positions.rs:364:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:320:9
+  --> $DIR/disallowed-positions.rs:364:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:320:31
+  --> $DIR/disallowed-positions.rs:364:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:320:31
+  --> $DIR/disallowed-positions.rs:364:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:324:9
+  --> $DIR/disallowed-positions.rs:368:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:324:9
+  --> $DIR/disallowed-positions.rs:368:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:90:8
+  --> $DIR/disallowed-positions.rs:92:8
    |
 LL |     if &let 0 = 0 {}
    |        ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -985,19 +1117,19 @@ LL +     if let 0 = 0 {}
    |
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:94:8
+  --> $DIR/disallowed-positions.rs:96:8
    |
 LL |     if *let 0 = 0 {}
    |        ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:96:8
+  --> $DIR/disallowed-positions.rs:98:8
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:104:8
+  --> $DIR/disallowed-positions.rs:106:8
    |
 LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1005,7 +1137,7 @@ LL |     if (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:104:19
+  --> $DIR/disallowed-positions.rs:106:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -1015,14 +1147,14 @@ LL | |
 LL | |     if (let 0 = 0)? {}
    | |                   ^ cannot use the `?` operator in a function that returns `()`
 ...  |
-LL | |     if let true = let true = true {}
+LL | |
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:114:8
+  --> $DIR/disallowed-positions.rs:116:8
    |
 LL |     if x = let 0 = 0 {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -1033,7 +1165,7 @@ LL |     if x == let 0 = 0 {}
    |          ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:117:8
+  --> $DIR/disallowed-positions.rs:119:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1042,7 +1174,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:119:8
+  --> $DIR/disallowed-positions.rs:121:8
    |
 LL |     if ..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -1051,7 +1183,7 @@ LL |     if ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:121:8
+  --> $DIR/disallowed-positions.rs:123:8
    |
 LL |     if (let 0 = 0).. {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -1060,7 +1192,7 @@ LL |     if (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:125:12
+  --> $DIR/disallowed-positions.rs:127:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1071,7 +1203,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:125:8
+  --> $DIR/disallowed-positions.rs:127:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1080,7 +1212,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:129:12
+  --> $DIR/disallowed-positions.rs:131:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1091,7 +1223,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:129:8
+  --> $DIR/disallowed-positions.rs:131:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1100,7 +1232,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:136:12
+  --> $DIR/disallowed-positions.rs:138:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1111,20 +1243,20 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:136:41
+  --> $DIR/disallowed-positions.rs:138:41
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:136:41: 136:48]`
+           found closure `[closure@$DIR/disallowed-positions.rs:138:41: 138:48]`
 help: use parentheses to call this closure
    |
 LL |     if let Range { start: F, end } = F..(|| true)() {}
    |                                         +       +++
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:136:8
+  --> $DIR/disallowed-positions.rs:138:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1133,7 +1265,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:144:12
+  --> $DIR/disallowed-positions.rs:146:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1144,7 +1276,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:144:44
+  --> $DIR/disallowed-positions.rs:146:44
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |                                            ^^^^^^^ expected `bool`, found `&&bool`
@@ -1156,7 +1288,7 @@ LL +     if let Range { start: true, end } = t..false {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:144:8
+  --> $DIR/disallowed-positions.rs:146:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1165,7 +1297,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:100:20
+  --> $DIR/disallowed-positions.rs:102:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1173,7 +1305,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:154:11
+  --> $DIR/disallowed-positions.rs:157:11
    |
 LL |     while &let 0 = 0 {}
    |           ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -1185,19 +1317,19 @@ LL +     while let 0 = 0 {}
    |
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:158:11
+  --> $DIR/disallowed-positions.rs:161:11
    |
 LL |     while *let 0 = 0 {}
    |           ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:160:11
+  --> $DIR/disallowed-positions.rs:163:11
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:168:11
+  --> $DIR/disallowed-positions.rs:171:11
    |
 LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1205,7 +1337,7 @@ LL |     while (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:168:22
+  --> $DIR/disallowed-positions.rs:171:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -1215,14 +1347,14 @@ LL | |
 LL | |     while (let 0 = 0)? {}
    | |                      ^ cannot use the `?` operator in a function that returns `()`
 ...  |
-LL | |     while let true = let true = true {}
+LL | |
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:178:11
+  --> $DIR/disallowed-positions.rs:181:11
    |
 LL |     while x = let 0 = 0 {}
    |           ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -1233,7 +1365,7 @@ LL |     while x == let 0 = 0 {}
    |             ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:181:11
+  --> $DIR/disallowed-positions.rs:184:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1242,7 +1374,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:183:11
+  --> $DIR/disallowed-positions.rs:186:11
    |
 LL |     while ..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -1251,7 +1383,7 @@ LL |     while ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:185:11
+  --> $DIR/disallowed-positions.rs:188:11
    |
 LL |     while (let 0 = 0).. {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -1260,7 +1392,7 @@ LL |     while (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:189:15
+  --> $DIR/disallowed-positions.rs:192:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1271,7 +1403,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:189:11
+  --> $DIR/disallowed-positions.rs:192:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1280,7 +1412,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:193:15
+  --> $DIR/disallowed-positions.rs:196:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1291,7 +1423,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:193:11
+  --> $DIR/disallowed-positions.rs:196:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1300,7 +1432,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:200:15
+  --> $DIR/disallowed-positions.rs:203:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1311,20 +1443,20 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:200:44
+  --> $DIR/disallowed-positions.rs:203:44
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:200:44: 200:51]`
+           found closure `[closure@$DIR/disallowed-positions.rs:203:44: 203:51]`
 help: use parentheses to call this closure
    |
 LL |     while let Range { start: F, end } = F..(|| true)() {}
    |                                            +       +++
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:200:11
+  --> $DIR/disallowed-positions.rs:203:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1333,7 +1465,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:208:15
+  --> $DIR/disallowed-positions.rs:211:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1344,7 +1476,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:208:47
+  --> $DIR/disallowed-positions.rs:211:47
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |                                               ^^^^^^^ expected `bool`, found `&&bool`
@@ -1356,7 +1488,7 @@ LL +     while let Range { start: true, end } = t..false {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:208:11
+  --> $DIR/disallowed-positions.rs:211:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1365,7 +1497,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:164:23
+  --> $DIR/disallowed-positions.rs:167:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1373,19 +1505,19 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:231:5
+  --> $DIR/disallowed-positions.rs:239:5
    |
 LL |     *let 0 = 0;
    |     ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:233:5
+  --> $DIR/disallowed-positions.rs:243:5
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:241:5
+  --> $DIR/disallowed-positions.rs:253:5
    |
 LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1393,12 +1525,12 @@ LL |     (let 0 = 0)?;
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:241:16
+  --> $DIR/disallowed-positions.rs:253:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
 LL | |
-LL | |     !let 0 = 0;
+LL | |
 ...  |
 LL | |     (let 0 = 0)?;
    | |                ^ cannot use the `?` operator in a function that returns `()`
@@ -1410,7 +1542,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:256:10
+  --> $DIR/disallowed-positions.rs:284:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1421,7 +1553,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:264:5
+  --> $DIR/disallowed-positions.rs:307:5
    |
 LL | fn outside_if_and_while_expr() {
    |                                - help: try adding a return type: `-> &bool`
@@ -1430,14 +1562,14 @@ LL |     &let 0 = 0
    |     ^^^^^^^^^^ expected `()`, found `&bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:237:17
+  --> $DIR/disallowed-positions.rs:249:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 134 previous errors
+error: aborting due to 156 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
index e66caa19ec9..12befc637c7 100644
--- a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
@@ -17,6 +17,7 @@ fn main() {
     //~| ERROR `let` expressions are not supported here
     //~| ERROR mismatched types
     //~| ERROR mismatched types
+    //~| ERROR expected expression, found `let` statement
         return;
     };
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr
index eea8ed0c963..498a112fa9b 100644
--- a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr
@@ -9,6 +9,12 @@ help: wrap the expression in parentheses
 LL |     let Some(n) = (opt && n == 1) else {
    |                   +             +
 
+error: expected expression, found `let` statement
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:26
+   |
+LL |     let Some(n) = opt && let another = n else {
+   |                          ^^^
+
 error: a `&&` expression cannot be directly assigned in `let...else`
   --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:19
    |
@@ -21,43 +27,43 @@ LL |     let Some(n) = (opt && let another = n) else {
    |                   +                      +
 
 error: this `if` expression is missing a block after the condition
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:23:5
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:5
    |
 LL |     if let Some(n) = opt else {
    |     ^^
    |
 help: add a block here
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:23:25
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:25
    |
 LL |     if let Some(n) = opt else {
    |                         ^
 
 error: this `if` expression is missing a block after the condition
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:27:5
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:5
    |
 LL |     if let Some(n) = opt && n == 1 else {
    |     ^^
    |
 help: add a block here
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:27:35
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:35
    |
 LL |     if let Some(n) = opt && n == 1 else {
    |                                   ^
 
 error: this `if` expression is missing a block after the condition
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:31:5
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:32:5
    |
 LL |     if let Some(n) = opt && let another = n else {
    |     ^^
    |
 help: add a block here
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:31:44
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:32:44
    |
 LL |     if let Some(n) = opt && let another = n else {
    |                                            ^
 
 error: expected `{`, found keyword `else`
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:37:33
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:38:33
    |
 LL |         while let Some(n) = opt else {
    |         ----- ----------------- ^^^^ expected `{`
@@ -66,7 +72,7 @@ LL |         while let Some(n) = opt else {
    |         while parsing the body of this `while` expression
 
 error: expected `{`, found keyword `else`
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:43:43
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:44:43
    |
 LL |         while let Some(n) = opt && n == 1 else {
    |         ----- --------------------------- ^^^^ expected `{`
@@ -75,7 +81,7 @@ LL |         while let Some(n) = opt && n == 1 else {
    |         while parsing the body of this `while` expression
 
 error: expected `{`, found keyword `else`
-  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:49:52
+  --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:50:52
    |
 LL |         while let Some(n) = opt && let another = n else {
    |         ----- ------------------------------------ ^^^^ expected `{`
@@ -131,6 +137,6 @@ LL |     let Some(n) = opt && let another = n else {
    = note: expected type `bool`
               found enum `Option<_>`
 
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
index ac60bc7e57f..87718211308 100644
--- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
@@ -39,6 +39,7 @@ fn _macros() {
 
     noop_expr!((let 0 = 1));
     //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR expected expression, found `let` statement
 
     macro_rules! use_expr {
         ($e:expr) => {
@@ -48,9 +49,9 @@ fn _macros() {
     }
     #[cfg(FALSE)] (let 0 = 1);
     //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR expected expression, found `let` statement
     use_expr!(let 0 = 1);
     //~^ ERROR no rules expected the token `let`
-    // ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`.
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
index 1eabee47c64..bcea8bbaa73 100644
--- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
@@ -1,5 +1,17 @@
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:50:20
+   |
+LL |     #[cfg(FALSE)] (let 0 = 1);
+   |                    ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:40:17
+   |
+LL |     noop_expr!((let 0 = 1));
+   |                 ^^^
+
 error: no rules expected the token `let`
-  --> $DIR/feature-gate.rs:51:15
+  --> $DIR/feature-gate.rs:53:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -62,7 +74,7 @@ LL |     while let Range { start: _, end: _ } = (true..true) && false {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:49:20
+  --> $DIR/feature-gate.rs:50:20
    |
 LL |     #[cfg(FALSE)] (let 0 = 1);
    |                    ^^^^^^^^^
@@ -79,6 +91,6 @@ LL |     noop_expr!((let 0 = 1));
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
-error: aborting due to 9 previous errors
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs b/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
new file mode 100644
index 00000000000..6cc53a1935b
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
@@ -0,0 +1,17 @@
+// check-pass
+// known-bug
+
+#![feature(let_chains)]
+
+fn main() {
+    let _opt = Some(1i32);
+
+    #[cfg(FALSE)]
+    {
+        if let Some(elem) = _opt && {
+            [1, 2, 3][let _ = ()];
+            true
+        } {
+        }
+    }
+}
diff --git a/src/test/ui/traits/issue-87558.rs b/src/test/ui/traits/issue-87558.rs
new file mode 100644
index 00000000000..c5d86bd637b
--- /dev/null
+++ b/src/test/ui/traits/issue-87558.rs
@@ -0,0 +1,9 @@
+struct ErrorKind;
+struct Error(ErrorKind);
+impl Fn(&isize) for Error {
+    //~^ ERROR manual implementations of `Fn` are experimental
+    //~| ERROR associated type bindings are not allowed here
+    fn from() {} //~ ERROR method `from` is not a member of trait `Fn`
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-87558.stderr b/src/test/ui/traits/issue-87558.stderr
new file mode 100644
index 00000000000..494274d8c30
--- /dev/null
+++ b/src/test/ui/traits/issue-87558.stderr
@@ -0,0 +1,24 @@
+error[E0407]: method `from` is not a member of trait `Fn`
+  --> $DIR/issue-87558.rs:6:5
+   |
+LL |     fn from() {}
+   |     ^^^^^^^^^^^^ not a member of trait `Fn`
+
+error[E0183]: manual implementations of `Fn` are experimental
+  --> $DIR/issue-87558.rs:3:6
+   |
+LL | impl Fn(&isize) for Error {
+   |      ^^^^^^^^^^ manual implementations of `Fn` are experimental
+   |
+   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
+
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-87558.rs:3:6
+   |
+LL | impl Fn(&isize) for Error {
+   |      ^^^^^^^^^^ associated type not allowed here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0183, E0229, E0407.
+For more information about an error, try `rustc --explain E0183`.