about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs50
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs7
-rw-r--r--compiler/rustc_errors/src/emitter.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs1
-rw-r--r--compiler/rustc_llvm/build.rs2
-rw-r--r--library/core/src/clone.rs33
-rw-r--r--library/core/src/internal_macros.rs38
-rw-r--r--library/core/src/net/ip_addr.rs47
-rw-r--r--library/core/src/num/nonzero.rs43
-rw-r--r--library/core/src/num/saturating.rs185
-rw-r--r--library/core/src/num/wrapping.rs224
-rw-r--r--library/core/src/ops/arith.rs82
-rw-r--r--library/core/src/ops/bit.rs102
-rw-r--r--library/core/src/time.rs27
-rw-r--r--library/std/src/sys/fs/windows.rs15
-rw-r--r--library/std/src/sys/io/io_slice/uefi.rs74
-rw-r--r--library/std/src/sys/io/mod.rs3
-rw-r--r--library/std/src/sys/pal/uefi/tests.rs119
-rw-r--r--library/std/src/sys/process/windows.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs9
-rw-r--r--src/bootstrap/src/core/config/config.rs699
-rw-r--r--src/bootstrap/src/core/download.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs9
-rw-r--r--tests/codegen-llvm/issues/saturating-sub-index-139759.rs19
-rw-r--r--tests/ui/associated-types/unioned-keys-with-associated-type-23442.rs (renamed from tests/ui/issues/issue-23442.rs)1
-rw-r--r--tests/ui/attributes/lint_on_root.stderr11
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr66
-rw-r--r--tests/ui/autoref-autoderef/auto-deref-on-cow-regression-91489.rs (renamed from tests/ui/issues/issue-91489.rs)1
-rw-r--r--tests/ui/binding/struct-destructuring-repeated-bindings-9725.rs (renamed from tests/ui/issues/issue-9725.rs)1
-rw-r--r--tests/ui/binding/struct-destructuring-repeated-bindings-9725.stderr (renamed from tests/ui/issues/issue-9725.stderr)4
-rw-r--r--tests/ui/borrowck/borrowck-in-static.stderr1
-rw-r--r--tests/ui/borrowck/borrowck-move-by-capture.stderr5
-rw-r--r--tests/ui/borrowck/issue-103624.stderr5
-rw-r--r--tests/ui/borrowck/issue-87456-point-to-closure.stderr5
-rw-r--r--tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr5
-rw-r--r--tests/ui/cast/constant-expression-cast-9942.rs (renamed from tests/ui/issues/issue-9942.rs)1
-rw-r--r--tests/ui/closures/closure-type-inference-in-context-9129.rs (renamed from tests/ui/issues/issue-9129.rs)1
-rw-r--r--tests/ui/coercion/trait-object-coercion-distribution-9951.rs (renamed from tests/ui/issues/issue-9951.rs)1
-rw-r--r--tests/ui/coercion/trait-object-coercion-distribution-9951.stderr (renamed from tests/ui/issues/issue-9951.stderr)2
-rw-r--r--tests/ui/const-generics/try-from-with-const-genericsrs-98299.rs (renamed from tests/ui/issues/issue-98299.rs)1
-rw-r--r--tests/ui/const-generics/try-from-with-const-genericsrs-98299.stderr (renamed from tests/ui/issues/issue-98299.stderr)12
-rw-r--r--tests/ui/cross-crate/auxiliary/aux-9155.rs (renamed from tests/ui/issues/auxiliary/issue-9155.rs)0
-rw-r--r--tests/ui/cross-crate/auxiliary/aux-9906.rs (renamed from tests/ui/issues/auxiliary/issue-9906.rs)0
-rw-r--r--tests/ui/cross-crate/generic-newtypes-cross-crate-usage-9155.rs11
-rw-r--r--tests/ui/cross-crate/reexported-structs-impls-link-error-9906.rs10
-rw-r--r--tests/ui/deref/dereferenceable-type-behavior-22992.rs (renamed from tests/ui/issues/issue-22992.rs)2
-rw-r--r--tests/ui/drop/multiple-drop-safe-code-25549.rs (renamed from tests/ui/issues/issue-25549-multiple-drop.rs)1
-rw-r--r--tests/ui/drop/static-variable-with-drop-trait-9243.rs (renamed from tests/ui/issues/issue-9243.rs)1
-rw-r--r--tests/ui/editions/edition-specific-identifier-shadowing-53333.rs (renamed from tests/ui/issues/issue-53333.rs)1
-rw-r--r--tests/ui/enum-discriminant/enum-discriminant-const-eval-truncation-9837.rs (renamed from tests/ui/issues/issue-9837.rs)1
-rw-r--r--tests/ui/enum/single-variant-enum-deref-error-9814.rs (renamed from tests/ui/issues/issue-9814.rs)1
-rw-r--r--tests/ui/enum/single-variant-enum-deref-error-9814.stderr (renamed from tests/ui/issues/issue-9814.stderr)2
-rw-r--r--tests/ui/enum/zero-variant-enum-pattern-matching-3037.rs (renamed from tests/ui/issues/issue-3037.rs)1
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr11
-rw-r--r--tests/ui/imports/auxiliary/aux-9968.rs (renamed from tests/ui/issues/auxiliary/issue-9968.rs)0
-rw-r--r--tests/ui/imports/pub-use-link-errors-9968.rs12
-rw-r--r--tests/ui/issues/issue-4335.stderr1
-rw-r--r--tests/ui/issues/issue-9155.rs11
-rw-r--r--tests/ui/issues/issue-9906.rs10
-rw-r--r--tests/ui/issues/issue-9968.rs12
-rw-r--r--tests/ui/iterators/for-loop-over-mut-iterator-21655.rs (renamed from tests/ui/issues/issue-21655.rs)1
-rw-r--r--tests/ui/lifetimes/struct-with-lifetime-parameters-9259.rs (renamed from tests/ui/issues/issue-9259.rs)1
-rw-r--r--tests/ui/link-native-libs/link-attr-validation-early.stderr22
-rw-r--r--tests/ui/lint/unused-results-lint-triggered-by-derive-debug-29710.rs (renamed from tests/ui/issues/issue-29710.rs)1
-rw-r--r--tests/ui/loops/loop-with-label-9047.rs (renamed from tests/ui/issues/issue-9047.rs)1
-rw-r--r--tests/ui/macros/issue-111749.stderr11
-rw-r--r--tests/ui/macros/macro-expansion-module-structure-9110.rs (renamed from tests/ui/issues/issue-9110.rs)1
-rw-r--r--tests/ui/macros/macro-invocation-with-variable-in-scope-9737.rs (renamed from tests/ui/issues/issue-9737.rs)1
-rw-r--r--tests/ui/macros/private-struct-member-macro-access-25386.rs (renamed from tests/ui/issues/issue-25386.rs)1
-rw-r--r--tests/ui/macros/private-struct-member-macro-access-25386.stderr (renamed from tests/ui/issues/issue-25386.stderr)2
-rw-r--r--tests/ui/malformed/malformed-regressions.stderr55
-rw-r--r--tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.fixed (renamed from tests/ui/issues/issue-92741.fixed)1
-rw-r--r--tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.rs (renamed from tests/ui/issues/issue-92741.rs)1
-rw-r--r--tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.stderr (renamed from tests/ui/issues/issue-92741.stderr)6
-rw-r--r--tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr5
-rw-r--r--tests/ui/nll/issue-52663-span-decl-captured-variable.stderr5
-rw-r--r--tests/ui/packed/misaligned-reference-drop-field-99838.rs (renamed from tests/ui/issues/issue-99838.rs)1
-rw-r--r--tests/ui/pattern/unit-variant-pattern-matching-29383.rs (renamed from tests/ui/issues/issue-pr29383.rs)1
-rw-r--r--tests/ui/pattern/unit-variant-pattern-matching-29383.stderr (renamed from tests/ui/issues/issue-pr29383.stderr)4
-rw-r--r--tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr1
-rw-r--r--tests/ui/static/static-string-slice-9249.rs (renamed from tests/ui/issues/issue-9249.rs)1
-rw-r--r--tests/ui/structs/struct-field-access-errors-24365.rs (renamed from tests/ui/issues/issue-24365.rs)1
-rw-r--r--tests/ui/structs/struct-field-access-errors-24365.stderr (renamed from tests/ui/issues/issue-24365.stderr)6
-rw-r--r--tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs161
-rw-r--r--tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr671
-rw-r--r--tests/ui/suggestions/option-content-move2.stderr11
-rw-r--r--tests/ui/suggestions/option-content-move3.stderr12
-rw-r--r--tests/ui/thread-local/thread-local-with-attributes-30756.rs (renamed from tests/ui/issues/issue-30756.rs)1
-rw-r--r--tests/ui/typeck/unused-type-parameter-span-30236.rs (renamed from tests/ui/issues/issue-30236.rs)1
-rw-r--r--tests/ui/typeck/unused-type-parameter-span-30236.stderr (renamed from tests/ui/issues/issue-30236.stderr)2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr22
-rw-r--r--tests/ui/uninhabited/uninhabited-type-layout-computation-88150.rs (renamed from tests/ui/issues/issue-88150.rs)1
94 files changed, 2433 insertions, 641 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 1067f1e40ef..af71db69483 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -9,7 +9,8 @@ use rustc_middle::bug;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
-use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
+use rustc_span::def_id::DefId;
+use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span};
 use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 use rustc_trait_selection::infer::InferCtxtExt;
 use tracing::debug;
@@ -507,12 +508,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 );
 
                 let closure_span = tcx.def_span(def_id);
+
                 self.cannot_move_out_of(span, &place_description)
                     .with_span_label(upvar_span, "captured outer variable")
                     .with_span_label(
                         closure_span,
                         format!("captured by this `{closure_kind}` closure"),
                     )
+                    .with_span_help(
+                        self.get_closure_bound_clause_span(*def_id),
+                        "`Fn` and `FnMut` closures require captured values to be able to be \
+                         consumed multiple times, but an `FnOnce` consume them only once",
+                    )
             }
             _ => {
                 let source = self.borrowed_content_source(deref_base);
@@ -561,6 +568,47 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         err
     }
 
+    fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
+        let tcx = self.infcx.tcx;
+        let typeck_result = tcx.typeck(self.mir_def_id());
+        // Check whether the closure is an argument to a call, if so,
+        // get the instantiated where-bounds of that call.
+        let closure_hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
+        let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return DUMMY_SP };
+
+        let predicates = match parent.kind {
+            hir::ExprKind::Call(callee, _) => {
+                let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP };
+                let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP };
+                tcx.predicates_of(fn_def_id).instantiate(tcx, args)
+            }
+            hir::ExprKind::MethodCall(..) => {
+                let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
+                    return DUMMY_SP;
+                };
+                let args = typeck_result.node_args(parent.hir_id);
+                tcx.predicates_of(method).instantiate(tcx, args)
+            }
+            _ => return DUMMY_SP,
+        };
+
+        // Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`.
+        for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
+            if let Some(clause) = pred.as_trait_clause()
+                && let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
+                && *clause_closure_def_id == def_id
+                && (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
+                    || tcx.lang_items().fn_trait() == Some(clause.def_id()))
+            {
+                // Found `<TyOfCapturingClosure as FnMut>`
+                // We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
+                // could be changed to `FnOnce()` to avoid the move error.
+                return *span;
+            }
+        }
+        DUMMY_SP
+    }
+
     fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
         match error {
             GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 5a5563c7bb2..98be37fd84b 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -847,17 +847,18 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
         self
     }
 
+    with_fn! { with_span_help,
     /// Prints the span with some help above it.
     /// This is like [`Diag::help()`], but it gets its own span.
     #[rustc_lint_diagnostics]
-    pub fn span_help<S: Into<MultiSpan>>(
+    pub fn span_help(
         &mut self,
-        sp: S,
+        sp: impl Into<MultiSpan>,
         msg: impl Into<SubdiagMessage>,
     ) -> &mut Self {
         self.sub(Level::Help, msg, sp.into());
         self
-    }
+    } }
 
     /// Disallow attaching suggestions to this diagnostic.
     /// Any suggestions attached e.g. with the `span_suggestion_*` methods
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 0c839f94f7f..97c47fa9b9a 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -3546,7 +3546,7 @@ pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> Confu
 
         for (f, s) in iter::zip(found.chars(), suggested.chars()) {
             if f != s {
-                if f.to_lowercase().to_string() == s.to_lowercase().to_string() {
+                if f.eq_ignore_ascii_case(&s) {
                     // Check for case differences (any character that differs only in case)
                     if ascii_confusables.contains(&f) || ascii_confusables.contains(&s) {
                         has_case_diff = true;
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 37b236a2e26..08b0efb74a0 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -347,7 +347,7 @@ fn expand_macro_attr(
 
     if cx.trace_macros() {
         let msg = format!(
-            "expanding `$[{name}({})] {}`",
+            "expanding `#[{name}({})] {}`",
             pprust::tts_to_string(&args),
             pprust::tts_to_string(&body),
         );
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index e660b950262..bee80335f74 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -217,6 +217,7 @@ declare_lint! {
     @future_incompatible = FutureIncompatibleInfo {
         reason: FutureIncompatibilityReason::FutureReleaseError,
         reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
+        report_in_deps: true,
     };
     crate_level_only
 }
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 6c740156c4d..1394edcee6b 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -255,7 +255,7 @@ fn main() {
         println!("cargo:rustc-link-lib=kstat");
     }
 
-    if (target.starts_with("arm") && !target.contains("freebsd")) && !target.contains("ohos")
+    if (target.starts_with("arm") && !target.contains("freebsd") && !target.contains("ohos"))
         || target.starts_with("mips-")
         || target.starts_with("mipsel-")
         || target.starts_with("powerpc-")
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index e315c4fac08..0add77b2bc8 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -139,6 +139,34 @@ mod uninit;
 /// // Note: With the manual implementations the above line will compile.
 /// ```
 ///
+/// ## `Clone` and `PartialEq`/`Eq`
+/// `Clone` is intended for the duplication of objects. Consequently, when implementing
+/// both `Clone` and [`PartialEq`], the following property is expected to hold:
+/// ```text
+/// x == x -> x.clone() == x
+/// ```
+/// In other words, if an object compares equal to itself,
+/// its clone must also compare equal to the original.
+///
+/// For types that also implement [`Eq`] – for which `x == x` always holds –
+/// this implies that `x.clone() == x` must always be true.
+/// Standard library collections such as
+/// [`HashMap`], [`HashSet`], [`BTreeMap`], [`BTreeSet`] and [`BinaryHeap`]
+/// rely on their keys respecting this property for correct behavior.
+/// Furthermore, these collections require that cloning a key preserves the outcome of the
+/// [`Hash`] and [`Ord`] methods. Thankfully, this follows automatically from `x.clone() == x`
+/// if `Hash` and `Ord` are correctly implemented according to their own requirements.
+///
+/// When deriving both `Clone` and [`PartialEq`] using `#[derive(Clone, PartialEq)]`
+/// or when additionally deriving [`Eq`] using `#[derive(Clone, PartialEq, Eq)]`,
+/// then this property is automatically upheld – provided that it is satisfied by
+/// the underlying types.
+///
+/// Violating this property is a logic error. The behavior resulting from a logic error is not
+/// specified, but users of the trait must ensure that such logic errors do *not* result in
+/// undefined behavior. This means that `unsafe` code **must not** rely on this property
+/// being satisfied.
+///
 /// ## Additional implementors
 ///
 /// In addition to the [implementors listed below][impls],
@@ -152,6 +180,11 @@ mod uninit;
 ///   (even if the referent doesn't),
 ///   while variables captured by mutable reference never implement `Clone`.
 ///
+/// [`HashMap`]: ../../std/collections/struct.HashMap.html
+/// [`HashSet`]: ../../std/collections/struct.HashSet.html
+/// [`BTreeMap`]: ../../std/collections/struct.BTreeMap.html
+/// [`BTreeSet`]: ../../std/collections/struct.BTreeSet.html
+/// [`BinaryHeap`]: ../../std/collections/struct.BinaryHeap.html
 /// [impls]: #implementors
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "clone"]
diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs
index 2aaefba2468..f90818c7969 100644
--- a/library/core/src/internal_macros.rs
+++ b/library/core/src/internal_macros.rs
@@ -1,13 +1,9 @@
 // implements the unary operator "op &T"
 // based on "op T" where T is expected to be `Copy`able
 macro_rules! forward_ref_unop {
-    (impl $imp:ident, $method:ident for $t:ty) => {
-        forward_ref_unop!(impl $imp, $method for $t,
-                #[stable(feature = "rust1", since = "1.0.0")]);
-    };
-    (impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
-        #[$attr]
-        impl $imp for &$t {
+    (impl $imp:ident, $method:ident for $t:ty, $(#[$attr:meta])+) => {
+        $(#[$attr])+
+        impl const $imp for &$t {
             type Output = <$t as $imp>::Output;
 
             #[inline]
@@ -21,13 +17,9 @@ macro_rules! forward_ref_unop {
 // implements binary operators "&T op U", "T op &U", "&T op &U"
 // based on "T op U" where T and U are expected to be `Copy`able
 macro_rules! forward_ref_binop {
-    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
-        forward_ref_binop!(impl $imp, $method for $t, $u,
-                #[stable(feature = "rust1", since = "1.0.0")]);
-    };
-    (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
-        #[$attr]
-        impl<'a> $imp<$u> for &'a $t {
+    (impl $imp:ident, $method:ident for $t:ty, $u:ty, $(#[$attr:meta])+) => {
+        $(#[$attr])+
+        impl const $imp<$u> for &$t {
             type Output = <$t as $imp<$u>>::Output;
 
             #[inline]
@@ -37,8 +29,8 @@ macro_rules! forward_ref_binop {
             }
         }
 
-        #[$attr]
-        impl $imp<&$u> for $t {
+        $(#[$attr])+
+        impl const $imp<&$u> for $t {
             type Output = <$t as $imp<$u>>::Output;
 
             #[inline]
@@ -48,8 +40,8 @@ macro_rules! forward_ref_binop {
             }
         }
 
-        #[$attr]
-        impl $imp<&$u> for &$t {
+        $(#[$attr])+
+        impl const $imp<&$u> for &$t {
             type Output = <$t as $imp<$u>>::Output;
 
             #[inline]
@@ -64,13 +56,9 @@ macro_rules! forward_ref_binop {
 // implements "T op= &U", based on "T op= U"
 // where U is expected to be `Copy`able
 macro_rules! forward_ref_op_assign {
-    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
-        forward_ref_op_assign!(impl $imp, $method for $t, $u,
-                #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
-    };
-    (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
-        #[$attr]
-        impl $imp<&$u> for $t {
+    (impl $imp:ident, $method:ident for $t:ty, $u:ty, $(#[$attr:meta])+) => {
+        $(#[$attr])+
+        impl const $imp<&$u> for $t {
             #[inline]
             #[track_caller]
             fn $method(&mut self, other: &$u) {
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index 6adeb2aa3fd..87f2110034c 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -2,7 +2,6 @@ use super::display_buffer::DisplayBuffer;
 use crate::cmp::Ordering;
 use crate::fmt::{self, Write};
 use crate::hash::{Hash, Hasher};
-use crate::iter;
 use crate::mem::transmute;
 use crate::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
 
@@ -2348,20 +2347,24 @@ impl const From<[u16; 8]> for IpAddr {
 }
 
 #[stable(feature = "ip_bitops", since = "1.75.0")]
-impl Not for Ipv4Addr {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Not for Ipv4Addr {
     type Output = Ipv4Addr;
 
     #[inline]
     fn not(mut self) -> Ipv4Addr {
-        for octet in &mut self.octets {
-            *octet = !*octet;
+        let mut idx = 0;
+        while idx < 4 {
+            self.octets[idx] = !self.octets[idx];
+            idx += 1;
         }
         self
     }
 }
 
 #[stable(feature = "ip_bitops", since = "1.75.0")]
-impl Not for &'_ Ipv4Addr {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Not for &'_ Ipv4Addr {
     type Output = Ipv4Addr;
 
     #[inline]
@@ -2371,20 +2374,24 @@ impl Not for &'_ Ipv4Addr {
 }
 
 #[stable(feature = "ip_bitops", since = "1.75.0")]
-impl Not for Ipv6Addr {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Not for Ipv6Addr {
     type Output = Ipv6Addr;
 
     #[inline]
     fn not(mut self) -> Ipv6Addr {
-        for octet in &mut self.octets {
-            *octet = !*octet;
+        let mut idx = 0;
+        while idx < 16 {
+            self.octets[idx] = !self.octets[idx];
+            idx += 1;
         }
         self
     }
 }
 
 #[stable(feature = "ip_bitops", since = "1.75.0")]
-impl Not for &'_ Ipv6Addr {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Not for &'_ Ipv6Addr {
     type Output = Ipv6Addr;
 
     #[inline]
@@ -2400,23 +2407,25 @@ macro_rules! bitop_impls {
     )*) => {
         $(
             $(#[$attr])*
-            impl $BitOpAssign for $ty {
+            impl const $BitOpAssign for $ty {
                 fn $bitop_assign(&mut self, rhs: $ty) {
-                    for (lhs, rhs) in iter::zip(&mut self.octets, rhs.octets) {
-                        lhs.$bitop_assign(rhs);
+                    let mut idx = 0;
+                    while idx < self.octets.len() {
+                        self.octets[idx].$bitop_assign(rhs.octets[idx]);
+                        idx += 1;
                     }
                 }
             }
 
             $(#[$attr])*
-            impl $BitOpAssign<&'_ $ty> for $ty {
+            impl const $BitOpAssign<&'_ $ty> for $ty {
                 fn $bitop_assign(&mut self, rhs: &'_ $ty) {
                     self.$bitop_assign(*rhs);
                 }
             }
 
             $(#[$attr])*
-            impl $BitOp for $ty {
+            impl const $BitOp for $ty {
                 type Output = $ty;
 
                 #[inline]
@@ -2427,7 +2436,7 @@ macro_rules! bitop_impls {
             }
 
             $(#[$attr])*
-            impl $BitOp<&'_ $ty> for $ty {
+            impl const $BitOp<&'_ $ty> for $ty {
                 type Output = $ty;
 
                 #[inline]
@@ -2438,7 +2447,7 @@ macro_rules! bitop_impls {
             }
 
             $(#[$attr])*
-            impl $BitOp<$ty> for &'_ $ty {
+            impl const $BitOp<$ty> for &'_ $ty {
                 type Output = $ty;
 
                 #[inline]
@@ -2450,7 +2459,7 @@ macro_rules! bitop_impls {
             }
 
             $(#[$attr])*
-            impl $BitOp<&'_ $ty> for &'_ $ty {
+            impl const $BitOp<&'_ $ty> for &'_ $ty {
                 type Output = $ty;
 
                 #[inline]
@@ -2466,12 +2475,16 @@ macro_rules! bitop_impls {
 
 bitop_impls! {
     #[stable(feature = "ip_bitops", since = "1.75.0")]
+    #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
     impl (BitAnd, BitAndAssign) for Ipv4Addr = (bitand, bitand_assign);
     #[stable(feature = "ip_bitops", since = "1.75.0")]
+    #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
     impl (BitOr, BitOrAssign) for Ipv4Addr = (bitor, bitor_assign);
 
     #[stable(feature = "ip_bitops", since = "1.75.0")]
+    #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
     impl (BitAnd, BitAndAssign) for Ipv6Addr = (bitand, bitand_assign);
     #[stable(feature = "ip_bitops", since = "1.75.0")]
+    #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
     impl (BitOr, BitOrAssign) for Ipv6Addr = (bitor, bitor_assign);
 }
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 08a66361e6f..308d722f5d5 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -310,9 +310,10 @@ where
 }
 
 #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-impl<T> BitOr for NonZero<T>
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl<T> const BitOr for NonZero<T>
 where
-    T: ZeroablePrimitive + BitOr<Output = T>,
+    T: ZeroablePrimitive + [const] BitOr<Output = T>,
 {
     type Output = Self;
 
@@ -324,9 +325,10 @@ where
 }
 
 #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-impl<T> BitOr<T> for NonZero<T>
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl<T> const BitOr<T> for NonZero<T>
 where
-    T: ZeroablePrimitive + BitOr<Output = T>,
+    T: ZeroablePrimitive + [const] BitOr<Output = T>,
 {
     type Output = Self;
 
@@ -338,9 +340,10 @@ where
 }
 
 #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-impl<T> BitOr<NonZero<T>> for T
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl<T> const BitOr<NonZero<T>> for T
 where
-    T: ZeroablePrimitive + BitOr<Output = T>,
+    T: ZeroablePrimitive + [const] BitOr<Output = T>,
 {
     type Output = NonZero<T>;
 
@@ -352,10 +355,11 @@ where
 }
 
 #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-impl<T> BitOrAssign for NonZero<T>
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl<T> const BitOrAssign for NonZero<T>
 where
     T: ZeroablePrimitive,
-    Self: BitOr<Output = Self>,
+    Self: [const] BitOr<Output = Self>,
 {
     #[inline]
     fn bitor_assign(&mut self, rhs: Self) {
@@ -364,10 +368,11 @@ where
 }
 
 #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-impl<T> BitOrAssign<T> for NonZero<T>
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl<T> const BitOrAssign<T> for NonZero<T>
 where
     T: ZeroablePrimitive,
-    Self: BitOr<T, Output = Self>,
+    Self: [const] BitOr<T, Output = Self>,
 {
     #[inline]
     fn bitor_assign(&mut self, rhs: T) {
@@ -1239,7 +1244,8 @@ macro_rules! nonzero_integer_signedness_dependent_impls {
     // Impls for unsigned nonzero types only.
     (unsigned $Int:ty) => {
         #[stable(feature = "nonzero_div", since = "1.51.0")]
-        impl Div<NonZero<$Int>> for $Int {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Div<NonZero<$Int>> for $Int {
             type Output = $Int;
 
             /// Same as `self / other.get()`, but because `other` is a `NonZero<_>`,
@@ -1257,7 +1263,8 @@ macro_rules! nonzero_integer_signedness_dependent_impls {
         }
 
         #[stable(feature = "nonzero_div_assign", since = "1.79.0")]
-        impl DivAssign<NonZero<$Int>> for $Int {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const DivAssign<NonZero<$Int>> for $Int {
             /// Same as `self /= other.get()`, but because `other` is a `NonZero<_>`,
             /// there's never a runtime check for division-by-zero.
             ///
@@ -1270,7 +1277,8 @@ macro_rules! nonzero_integer_signedness_dependent_impls {
         }
 
         #[stable(feature = "nonzero_div", since = "1.51.0")]
-        impl Rem<NonZero<$Int>> for $Int {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Rem<NonZero<$Int>> for $Int {
             type Output = $Int;
 
             /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
@@ -1283,7 +1291,8 @@ macro_rules! nonzero_integer_signedness_dependent_impls {
         }
 
         #[stable(feature = "nonzero_div_assign", since = "1.79.0")]
-        impl RemAssign<NonZero<$Int>> for $Int {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const RemAssign<NonZero<$Int>> for $Int {
             /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
             #[inline]
             fn rem_assign(&mut self, other: NonZero<$Int>) {
@@ -1323,7 +1332,8 @@ macro_rules! nonzero_integer_signedness_dependent_impls {
     // Impls for signed nonzero types only.
     (signed $Int:ty) => {
         #[stable(feature = "signed_nonzero_neg", since = "1.71.0")]
-        impl Neg for NonZero<$Int> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Neg for NonZero<$Int> {
             type Output = Self;
 
             #[inline]
@@ -1334,7 +1344,8 @@ macro_rules! nonzero_integer_signedness_dependent_impls {
         }
 
         forward_ref_unop! { impl Neg, neg for NonZero<$Int>,
-        #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] }
+        #[stable(feature = "signed_nonzero_neg", since = "1.71.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     };
 }
 
diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs
index 4460e430aec..c7040721b93 100644
--- a/library/core/src/num/saturating.rs
+++ b/library/core/src/num/saturating.rs
@@ -109,7 +109,8 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> {
 //         //         *self = *self << other;
 //         //     }
 //         // }
-//         // forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f }
+//         // forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f,
+//         // #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 //
 //         #[unstable(feature = "saturating_int_impl", issue = "87920")]
 //         impl Shr<$f> for Saturating<$t> {
@@ -134,7 +135,8 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> {
 //                 *self = *self >> other;
 //             }
 //         }
-//         forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f }
+//         forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f,
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 //     };
 // }
 //
@@ -159,7 +161,8 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> {
 //                 *self = *self << other;
 //             }
 //         }
-//         forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f }
+//         forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f,
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 //
 //         #[unstable(feature = "saturating_int_impl", issue = "87920")]
 //         impl Shr<$f> for Saturating<$t> {
@@ -180,7 +183,8 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> {
 //                 *self = *self >> other;
 //             }
 //         }
-//         forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f }
+//         forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f,
+//         #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 //     };
 // }
 //
@@ -209,7 +213,8 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> {
 macro_rules! saturating_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl Add for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Add for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -218,28 +223,36 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl AddAssign for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const AddAssign for Saturating<$t> {
             #[inline]
             fn add_assign(&mut self, other: Saturating<$t>) {
                 *self = *self + other;
             }
         }
-        forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t> }
+        forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t>,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")]
-        impl AddAssign<$t> for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const AddAssign<$t> for Saturating<$t> {
             #[inline]
             fn add_assign(&mut self, other: $t) {
                 *self = *self + Saturating(other);
             }
         }
-        forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t }
+        forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl Sub for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Sub for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -248,28 +261,36 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl SubAssign for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const SubAssign for Saturating<$t> {
             #[inline]
             fn sub_assign(&mut self, other: Saturating<$t>) {
                 *self = *self - other;
             }
         }
-        forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t> }
+        forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t>,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")]
-        impl SubAssign<$t> for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const SubAssign<$t> for Saturating<$t> {
             #[inline]
             fn sub_assign(&mut self, other: $t) {
                 *self = *self - Saturating(other);
             }
         }
-        forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t }
+        forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl Mul for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Mul for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -278,25 +299,32 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl MulAssign for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const MulAssign for Saturating<$t> {
             #[inline]
             fn mul_assign(&mut self, other: Saturating<$t>) {
                 *self = *self * other;
             }
         }
-        forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t> }
+        forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t>,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")]
-        impl MulAssign<$t> for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const MulAssign<$t> for Saturating<$t> {
             #[inline]
             fn mul_assign(&mut self, other: $t) {
                 *self = *self * Saturating(other);
             }
         }
-        forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, $t }
+        forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, $t,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         /// # Examples
         ///
@@ -314,7 +342,8 @@ macro_rules! saturating_impl {
         #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / Saturating(0);")]
         /// ```
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl Div for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Div for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -323,29 +352,36 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
-
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl DivAssign for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const DivAssign for Saturating<$t> {
             #[inline]
             fn div_assign(&mut self, other: Saturating<$t>) {
                 *self = *self / other;
             }
         }
-        forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, Saturating<$t> }
+        forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, Saturating<$t>,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")]
-        impl DivAssign<$t> for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const DivAssign<$t> for Saturating<$t> {
             #[inline]
             fn div_assign(&mut self, other: $t) {
                 *self = *self / Saturating(other);
             }
         }
-        forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t }
+        forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl Rem for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Rem for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -354,28 +390,36 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl RemAssign for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const RemAssign for Saturating<$t> {
             #[inline]
             fn rem_assign(&mut self, other: Saturating<$t>) {
                 *self = *self % other;
             }
         }
-        forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, Saturating<$t> }
+        forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, Saturating<$t>,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")]
-        impl RemAssign<$t> for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const RemAssign<$t> for Saturating<$t> {
             #[inline]
             fn rem_assign(&mut self, other: $t) {
                 *self = *self % Saturating(other);
             }
         }
-        forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t }
+        forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl Not for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Not for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -384,10 +428,12 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_unop! { impl Not, not for Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl BitXor for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitXor for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -396,28 +442,36 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl BitXorAssign for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitXorAssign for Saturating<$t> {
             #[inline]
             fn bitxor_assign(&mut self, other: Saturating<$t>) {
                 *self = *self ^ other;
             }
         }
-        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, Saturating<$t> }
+        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, Saturating<$t>,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")]
-        impl BitXorAssign<$t> for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitXorAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitxor_assign(&mut self, other: $t) {
                 *self = *self ^ Saturating(other);
             }
         }
-        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t }
+        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl BitOr for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitOr for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -426,28 +480,36 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl BitOrAssign for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitOrAssign for Saturating<$t> {
             #[inline]
             fn bitor_assign(&mut self, other: Saturating<$t>) {
                 *self = *self | other;
             }
         }
-        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, Saturating<$t> }
+        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, Saturating<$t>,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")]
-        impl BitOrAssign<$t> for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitOrAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitor_assign(&mut self, other: $t) {
                 *self = *self | Saturating(other);
             }
         }
-        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t }
+        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl BitAnd for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitAnd for Saturating<$t> {
             type Output = Saturating<$t>;
 
             #[inline]
@@ -456,25 +518,32 @@ macro_rules! saturating_impl {
             }
         }
         forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl BitAndAssign for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitAndAssign for Saturating<$t> {
             #[inline]
             fn bitand_assign(&mut self, other: Saturating<$t>) {
                 *self = *self & other;
             }
         }
-        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, Saturating<$t> }
+        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, Saturating<$t>,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")]
-        impl BitAndAssign<$t> for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitAndAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitand_assign(&mut self, other: $t) {
                 *self = *self & Saturating(other);
             }
         }
-        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, $t }
+        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, $t,
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
     )*)
 }
@@ -931,7 +1000,8 @@ macro_rules! saturating_int_impl_signed {
         }
 
         #[stable(feature = "saturating_int_impl", since = "1.74.0")]
-        impl Neg for Saturating<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Neg for Saturating<$t> {
             type Output = Self;
             #[inline]
             fn neg(self) -> Self {
@@ -939,7 +1009,8 @@ macro_rules! saturating_int_impl_signed {
             }
         }
         forward_ref_unop! { impl Neg, neg for Saturating<$t>,
-                #[stable(feature = "saturating_int_impl", since = "1.74.0")] }
+        #[stable(feature = "saturating_int_impl", since = "1.74.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs
index c460f38bd2e..9ccad4b6459 100644
--- a/library/core/src/num/wrapping.rs
+++ b/library/core/src/num/wrapping.rs
@@ -88,7 +88,8 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Wrapping<T> {
 macro_rules! sh_impl_signed {
     ($t:ident, $f:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shl<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Shl<$f> for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -101,19 +102,24 @@ macro_rules! sh_impl_signed {
             }
         }
         forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
-        #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
+        #[stable(feature = "wrapping_ref_ops", since = "1.39.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShlAssign<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const ShlAssign<$f> for Wrapping<$t> {
             #[inline]
             fn shl_assign(&mut self, other: $f) {
                 *self = *self << other;
             }
         }
-        forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
+        forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shr<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Shr<$f> for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -126,23 +132,28 @@ macro_rules! sh_impl_signed {
             }
         }
         forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
-        #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
+        #[stable(feature = "wrapping_ref_ops", since = "1.39.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShrAssign<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const ShrAssign<$f> for Wrapping<$t> {
             #[inline]
             fn shr_assign(&mut self, other: $f) {
                 *self = *self >> other;
             }
         }
-        forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
+        forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     };
 }
 
 macro_rules! sh_impl_unsigned {
     ($t:ident, $f:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shl<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Shl<$f> for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -151,19 +162,24 @@ macro_rules! sh_impl_unsigned {
             }
         }
         forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
-        #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
+        #[stable(feature = "wrapping_ref_ops", since = "1.39.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShlAssign<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const ShlAssign<$f> for Wrapping<$t> {
             #[inline]
             fn shl_assign(&mut self, other: $f) {
                 *self = *self << other;
             }
         }
-        forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
+        forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shr<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Shr<$f> for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -172,16 +188,20 @@ macro_rules! sh_impl_unsigned {
             }
         }
         forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
-        #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
+        #[stable(feature = "wrapping_ref_ops", since = "1.39.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShrAssign<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const ShrAssign<$f> for Wrapping<$t> {
             #[inline]
             fn shr_assign(&mut self, other: $f) {
                 *self = *self >> other;
             }
         }
-        forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
+        forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     };
 }
 
@@ -210,7 +230,8 @@ sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 macro_rules! wrapping_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Add for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Add for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -219,28 +240,36 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl AddAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const AddAssign for Wrapping<$t> {
             #[inline]
             fn add_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self + other;
             }
         }
-        forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, Wrapping<$t>,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
-        impl AddAssign<$t> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const AddAssign<$t> for Wrapping<$t> {
             #[inline]
             fn add_assign(&mut self, other: $t) {
                 *self = *self + Wrapping(other);
             }
         }
-        forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, $t }
+        forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Sub for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Sub for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -249,28 +278,36 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl SubAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const SubAssign for Wrapping<$t> {
             #[inline]
             fn sub_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self - other;
             }
         }
-        forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t>,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
-        impl SubAssign<$t> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const SubAssign<$t> for Wrapping<$t> {
             #[inline]
             fn sub_assign(&mut self, other: $t) {
                 *self = *self - Wrapping(other);
             }
         }
-        forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, $t }
+        forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Mul for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Mul for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -279,28 +316,36 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_binop! { impl Mul, mul for Wrapping<$t>, Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl MulAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const MulAssign for Wrapping<$t> {
             #[inline]
             fn mul_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self * other;
             }
         }
-        forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t>,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
-        impl MulAssign<$t> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const MulAssign<$t> for Wrapping<$t> {
             #[inline]
             fn mul_assign(&mut self, other: $t) {
                 *self = *self * Wrapping(other);
             }
         }
-        forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, $t }
+        forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_div", since = "1.3.0")]
-        impl Div for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Div for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -309,28 +354,36 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl DivAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const DivAssign for Wrapping<$t> {
             #[inline]
             fn div_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self / other;
             }
         }
-        forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, Wrapping<$t>,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
-        impl DivAssign<$t> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const DivAssign<$t> for Wrapping<$t> {
             #[inline]
             fn div_assign(&mut self, other: $t) {
                 *self = *self / Wrapping(other);
             }
         }
-        forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, $t }
+        forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_impls", since = "1.7.0")]
-        impl Rem for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Rem for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -339,28 +392,36 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl RemAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const RemAssign for Wrapping<$t> {
             #[inline]
             fn rem_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self % other;
             }
         }
-        forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t>,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
-        impl RemAssign<$t> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const RemAssign<$t> for Wrapping<$t> {
             #[inline]
             fn rem_assign(&mut self, other: $t) {
                 *self = *self % Wrapping(other);
             }
         }
-        forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, $t }
+        forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Not for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Not for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -369,10 +430,12 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_unop! { impl Not, not for Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitXor for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitXor for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -381,28 +444,36 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitXorAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitXorAssign for Wrapping<$t> {
             #[inline]
             fn bitxor_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self ^ other;
             }
         }
-        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t>,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
-        impl BitXorAssign<$t> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitXorAssign<$t> for Wrapping<$t> {
             #[inline]
             fn bitxor_assign(&mut self, other: $t) {
                 *self = *self ^ Wrapping(other);
             }
         }
-        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, $t }
+        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitOr for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitOr for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -411,28 +482,36 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitOrAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitOrAssign for Wrapping<$t> {
             #[inline]
             fn bitor_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self | other;
             }
         }
-        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t>,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
-        impl BitOrAssign<$t> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitOrAssign<$t> for Wrapping<$t> {
             #[inline]
             fn bitor_assign(&mut self, other: $t) {
                 *self = *self | Wrapping(other);
             }
         }
-        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, $t }
+        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitAnd for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitAnd for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -441,28 +520,36 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitAndAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitAndAssign for Wrapping<$t> {
             #[inline]
             fn bitand_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self & other;
             }
         }
-        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t>,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
-        impl BitAndAssign<$t> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitAndAssign<$t> for Wrapping<$t> {
             #[inline]
             fn bitand_assign(&mut self, other: $t) {
                 *self = *self & Wrapping(other);
             }
         }
-        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, $t }
+        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
         #[stable(feature = "wrapping_neg", since = "1.10.0")]
-        impl Neg for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Neg for Wrapping<$t> {
             type Output = Self;
             #[inline]
             fn neg(self) -> Self {
@@ -470,7 +557,8 @@ macro_rules! wrapping_impl {
             }
         }
         forward_ref_unop! { impl Neg, neg for Wrapping<$t>,
-                #[stable(feature = "wrapping_ref", since = "1.14.0")] }
+        #[stable(feature = "wrapping_ref", since = "1.14.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
 
     )*)
 }
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index 7d44b1733b9..16c719b0c39 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -106,7 +106,9 @@ macro_rules! add_impl {
             fn add(self, other: $t) -> $t { self + other }
         }
 
-        forward_ref_binop! { impl Add, add for $t, $t }
+        forward_ref_binop! { impl Add, add for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -218,7 +220,9 @@ macro_rules! sub_impl {
             fn sub(self, other: $t) -> $t { self - other }
         }
 
-        forward_ref_binop! { impl Sub, sub for $t, $t }
+        forward_ref_binop! { impl Sub, sub for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -351,7 +355,9 @@ macro_rules! mul_impl {
             fn mul(self, other: $t) -> $t { self * other }
         }
 
-        forward_ref_binop! { impl Mul, mul for $t, $t }
+        forward_ref_binop! { impl Mul, mul for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -493,7 +499,9 @@ macro_rules! div_impl_integer {
             fn div(self, other: $t) -> $t { self / other }
         }
 
-        forward_ref_binop! { impl Div, div for $t, $t }
+        forward_ref_binop! { impl Div, div for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)*)
 }
 
@@ -513,7 +521,9 @@ macro_rules! div_impl_float {
             fn div(self, other: $t) -> $t { self / other }
         }
 
-        forward_ref_binop! { impl Div, div for $t, $t }
+        forward_ref_binop! { impl Div, div for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -599,7 +609,9 @@ macro_rules! rem_impl_integer {
             fn rem(self, other: $t) -> $t { self % other }
         }
 
-        forward_ref_binop! { impl Rem, rem for $t, $t }
+        forward_ref_binop! { impl Rem, rem for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)*)
 }
 
@@ -634,7 +646,9 @@ macro_rules! rem_impl_float {
             fn rem(self, other: $t) -> $t { self % other }
         }
 
-        forward_ref_binop! { impl Rem, rem for $t, $t }
+        forward_ref_binop! { impl Rem, rem for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -678,7 +692,9 @@ rem_impl_float! { f16 f32 f64 f128 }
 /// ```
 #[lang = "neg"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[doc(alias = "-")]
+#[const_trait]
 pub trait Neg {
     /// The resulting type after applying the `-` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -701,7 +717,8 @@ pub trait Neg {
 macro_rules! neg_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Neg for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Neg for $t {
             type Output = $t;
 
             #[inline]
@@ -709,7 +726,9 @@ macro_rules! neg_impl {
             fn neg(self) -> $t { -self }
         }
 
-        forward_ref_unop! { impl Neg, neg for $t }
+        forward_ref_unop! { impl Neg, neg for $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -746,12 +765,14 @@ neg_impl! { isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
 /// ```
 #[lang = "add_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "cannot add-assign `{Rhs}` to `{Self}`",
     label = "no implementation for `{Self} += {Rhs}`"
 )]
 #[doc(alias = "+")]
 #[doc(alias = "+=")]
+#[const_trait]
 pub trait AddAssign<Rhs = Self> {
     /// Performs the `+=` operation.
     ///
@@ -769,14 +790,17 @@ pub trait AddAssign<Rhs = Self> {
 macro_rules! add_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl AddAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const AddAssign for $t {
             #[inline]
             #[track_caller]
             #[rustc_inherit_overflow_checks]
             fn add_assign(&mut self, other: $t) { *self += other }
         }
 
-        forward_ref_op_assign! { impl AddAssign, add_assign for $t, $t }
+        forward_ref_op_assign! { impl AddAssign, add_assign for $t, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )+)
 }
 
@@ -813,12 +837,14 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f
 /// ```
 #[lang = "sub_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "cannot subtract-assign `{Rhs}` from `{Self}`",
     label = "no implementation for `{Self} -= {Rhs}`"
 )]
 #[doc(alias = "-")]
 #[doc(alias = "-=")]
+#[const_trait]
 pub trait SubAssign<Rhs = Self> {
     /// Performs the `-=` operation.
     ///
@@ -836,14 +862,17 @@ pub trait SubAssign<Rhs = Self> {
 macro_rules! sub_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl SubAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const SubAssign for $t {
             #[inline]
             #[track_caller]
             #[rustc_inherit_overflow_checks]
             fn sub_assign(&mut self, other: $t) { *self -= other }
         }
 
-        forward_ref_op_assign! { impl SubAssign, sub_assign for $t, $t }
+        forward_ref_op_assign! { impl SubAssign, sub_assign for $t, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )+)
 }
 
@@ -871,12 +900,14 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f
 /// ```
 #[lang = "mul_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "cannot multiply-assign `{Self}` by `{Rhs}`",
     label = "no implementation for `{Self} *= {Rhs}`"
 )]
 #[doc(alias = "*")]
 #[doc(alias = "*=")]
+#[const_trait]
 pub trait MulAssign<Rhs = Self> {
     /// Performs the `*=` operation.
     ///
@@ -894,14 +925,17 @@ pub trait MulAssign<Rhs = Self> {
 macro_rules! mul_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl MulAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const MulAssign for $t {
             #[inline]
             #[track_caller]
             #[rustc_inherit_overflow_checks]
             fn mul_assign(&mut self, other: $t) { *self *= other }
         }
 
-        forward_ref_op_assign! { impl MulAssign, mul_assign for $t, $t }
+        forward_ref_op_assign! { impl MulAssign, mul_assign for $t, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )+)
 }
 
@@ -929,12 +963,14 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f
 /// ```
 #[lang = "div_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "cannot divide-assign `{Self}` by `{Rhs}`",
     label = "no implementation for `{Self} /= {Rhs}`"
 )]
 #[doc(alias = "/")]
 #[doc(alias = "/=")]
+#[const_trait]
 pub trait DivAssign<Rhs = Self> {
     /// Performs the `/=` operation.
     ///
@@ -952,13 +988,16 @@ pub trait DivAssign<Rhs = Self> {
 macro_rules! div_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl DivAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const DivAssign for $t {
             #[inline]
             #[track_caller]
             fn div_assign(&mut self, other: $t) { *self /= other }
         }
 
-        forward_ref_op_assign! { impl DivAssign, div_assign for $t, $t }
+        forward_ref_op_assign! { impl DivAssign, div_assign for $t, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )+)
 }
 
@@ -990,12 +1029,14 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f
 /// ```
 #[lang = "rem_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "cannot calculate and assign the remainder of `{Self}` divided by `{Rhs}`",
     label = "no implementation for `{Self} %= {Rhs}`"
 )]
 #[doc(alias = "%")]
 #[doc(alias = "%=")]
+#[const_trait]
 pub trait RemAssign<Rhs = Self> {
     /// Performs the `%=` operation.
     ///
@@ -1013,13 +1054,16 @@ pub trait RemAssign<Rhs = Self> {
 macro_rules! rem_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl RemAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const RemAssign for $t {
             #[inline]
             #[track_caller]
             fn rem_assign(&mut self, other: $t) { *self %= other }
         }
 
-        forward_ref_op_assign! { impl RemAssign, rem_assign for $t, $t }
+        forward_ref_op_assign! { impl RemAssign, rem_assign for $t, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )+)
 }
 
diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs
index deb54c8ba34..00196728219 100644
--- a/library/core/src/ops/bit.rs
+++ b/library/core/src/ops/bit.rs
@@ -30,7 +30,9 @@
 /// ```
 #[lang = "not"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[doc(alias = "!")]
+#[const_trait]
 pub trait Not {
     /// The resulting type after applying the `!` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -54,21 +56,25 @@ pub trait Not {
 macro_rules! not_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Not for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Not for $t {
             type Output = $t;
 
             #[inline]
             fn not(self) -> $t { !self }
         }
 
-        forward_ref_unop! { impl Not, not for $t }
+        forward_ref_unop! { impl Not, not for $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
 not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
 #[stable(feature = "not_never", since = "1.60.0")]
-impl Not for ! {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Not for ! {
     type Output = !;
 
     #[inline]
@@ -137,10 +143,12 @@ impl Not for ! {
 #[lang = "bitand"]
 #[doc(alias = "&")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} & {Rhs}`",
     label = "no implementation for `{Self} & {Rhs}`"
 )]
+#[const_trait]
 pub trait BitAnd<Rhs = Self> {
     /// The resulting type after applying the `&` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -164,14 +172,17 @@ pub trait BitAnd<Rhs = Self> {
 macro_rules! bitand_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitAnd for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitAnd for $t {
             type Output = $t;
 
             #[inline]
             fn bitand(self, rhs: $t) -> $t { self & rhs }
         }
 
-        forward_ref_binop! { impl BitAnd, bitand for $t, $t }
+        forward_ref_binop! { impl BitAnd, bitand for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -237,10 +248,12 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 #[lang = "bitor"]
 #[doc(alias = "|")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} | {Rhs}`",
     label = "no implementation for `{Self} | {Rhs}`"
 )]
+#[const_trait]
 pub trait BitOr<Rhs = Self> {
     /// The resulting type after applying the `|` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -264,14 +277,17 @@ pub trait BitOr<Rhs = Self> {
 macro_rules! bitor_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitOr for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitOr for $t {
             type Output = $t;
 
             #[inline]
             fn bitor(self, rhs: $t) -> $t { self | rhs }
         }
 
-        forward_ref_binop! { impl BitOr, bitor for $t, $t }
+        forward_ref_binop! { impl BitOr, bitor for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -337,10 +353,12 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 #[lang = "bitxor"]
 #[doc(alias = "^")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} ^ {Rhs}`",
     label = "no implementation for `{Self} ^ {Rhs}`"
 )]
+#[const_trait]
 pub trait BitXor<Rhs = Self> {
     /// The resulting type after applying the `^` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -364,14 +382,17 @@ pub trait BitXor<Rhs = Self> {
 macro_rules! bitxor_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitXor for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitXor for $t {
             type Output = $t;
 
             #[inline]
             fn bitxor(self, other: $t) -> $t { self ^ other }
         }
 
-        forward_ref_binop! { impl BitXor, bitxor for $t, $t }
+        forward_ref_binop! { impl BitXor, bitxor for $t, $t,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )*)
 }
 
@@ -436,10 +457,12 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 #[lang = "shl"]
 #[doc(alias = "<<")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} << {Rhs}`",
     label = "no implementation for `{Self} << {Rhs}`"
 )]
+#[const_trait]
 pub trait Shl<Rhs = Self> {
     /// The resulting type after applying the `<<` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -461,7 +484,8 @@ pub trait Shl<Rhs = Self> {
 macro_rules! shl_impl {
     ($t:ty, $f:ty) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shl<$f> for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Shl<$f> for $t {
             type Output = $t;
 
             #[inline]
@@ -471,7 +495,9 @@ macro_rules! shl_impl {
             }
         }
 
-        forward_ref_binop! { impl Shl, shl for $t, $f }
+        forward_ref_binop! { impl Shl, shl for $t, $f,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     };
 }
 
@@ -554,10 +580,12 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 #[lang = "shr"]
 #[doc(alias = ">>")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} >> {Rhs}`",
     label = "no implementation for `{Self} >> {Rhs}`"
 )]
+#[const_trait]
 pub trait Shr<Rhs = Self> {
     /// The resulting type after applying the `>>` operator.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -579,7 +607,8 @@ pub trait Shr<Rhs = Self> {
 macro_rules! shr_impl {
     ($t:ty, $f:ty) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shr<$f> for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const Shr<$f> for $t {
             type Output = $t;
 
             #[inline]
@@ -589,7 +618,9 @@ macro_rules! shr_impl {
             }
         }
 
-        forward_ref_binop! { impl Shr, shr for $t, $f }
+        forward_ref_binop! { impl Shr, shr for $t, $f,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     };
 }
 
@@ -681,10 +712,12 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 #[lang = "bitand_assign"]
 #[doc(alias = "&=")]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} &= {Rhs}`",
     label = "no implementation for `{Self} &= {Rhs}`"
 )]
+#[const_trait]
 pub trait BitAndAssign<Rhs = Self> {
     /// Performs the `&=` operation.
     ///
@@ -714,12 +747,15 @@ pub trait BitAndAssign<Rhs = Self> {
 macro_rules! bitand_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitAndAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitAndAssign for $t {
             #[inline]
             fn bitand_assign(&mut self, other: $t) { *self &= other }
         }
 
-        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for $t, $t }
+        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for $t, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )+)
 }
 
@@ -752,10 +788,12 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 #[lang = "bitor_assign"]
 #[doc(alias = "|=")]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} |= {Rhs}`",
     label = "no implementation for `{Self} |= {Rhs}`"
 )]
+#[const_trait]
 pub trait BitOrAssign<Rhs = Self> {
     /// Performs the `|=` operation.
     ///
@@ -785,12 +823,15 @@ pub trait BitOrAssign<Rhs = Self> {
 macro_rules! bitor_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitOrAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitOrAssign for $t {
             #[inline]
             fn bitor_assign(&mut self, other: $t) { *self |= other }
         }
 
-        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for $t, $t }
+        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for $t, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )+)
 }
 
@@ -823,10 +864,12 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 #[lang = "bitxor_assign"]
 #[doc(alias = "^=")]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} ^= {Rhs}`",
     label = "no implementation for `{Self} ^= {Rhs}`"
 )]
+#[const_trait]
 pub trait BitXorAssign<Rhs = Self> {
     /// Performs the `^=` operation.
     ///
@@ -856,12 +899,15 @@ pub trait BitXorAssign<Rhs = Self> {
 macro_rules! bitxor_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitXorAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const BitXorAssign for $t {
             #[inline]
             fn bitxor_assign(&mut self, other: $t) { *self ^= other }
         }
 
-        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for $t, $t }
+        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for $t, $t,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     )+)
 }
 
@@ -892,10 +938,12 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 #[lang = "shl_assign"]
 #[doc(alias = "<<=")]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} <<= {Rhs}`",
     label = "no implementation for `{Self} <<= {Rhs}`"
 )]
+#[const_trait]
 pub trait ShlAssign<Rhs = Self> {
     /// Performs the `<<=` operation.
     ///
@@ -917,7 +965,8 @@ pub trait ShlAssign<Rhs = Self> {
 macro_rules! shl_assign_impl {
     ($t:ty, $f:ty) => {
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShlAssign<$f> for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const ShlAssign<$f> for $t {
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn shl_assign(&mut self, other: $f) {
@@ -925,7 +974,9 @@ macro_rules! shl_assign_impl {
             }
         }
 
-        forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $f }
+        forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $f,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     };
 }
 
@@ -974,10 +1025,12 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
 #[lang = "shr_assign"]
 #[doc(alias = ">>=")]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
 #[diagnostic::on_unimplemented(
     message = "no implementation for `{Self} >>= {Rhs}`",
     label = "no implementation for `{Self} >>= {Rhs}`"
 )]
+#[const_trait]
 pub trait ShrAssign<Rhs = Self> {
     /// Performs the `>>=` operation.
     ///
@@ -999,7 +1052,8 @@ pub trait ShrAssign<Rhs = Self> {
 macro_rules! shr_assign_impl {
     ($t:ty, $f:ty) => {
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShrAssign<$f> for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+        impl const ShrAssign<$f> for $t {
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn shr_assign(&mut self, other: $f) {
@@ -1007,7 +1061,9 @@ macro_rules! shr_assign_impl {
             }
         }
 
-        forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $f }
+        forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $f,
+        #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "143802")] }
     };
 }
 
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 9a0f5e0faef..0cc570f4b73 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -1100,7 +1100,8 @@ impl Duration {
 }
 
 #[stable(feature = "duration", since = "1.3.0")]
-impl Add for Duration {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Add for Duration {
     type Output = Duration;
 
     #[inline]
@@ -1110,7 +1111,8 @@ impl Add for Duration {
 }
 
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl AddAssign for Duration {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const AddAssign for Duration {
     #[inline]
     fn add_assign(&mut self, rhs: Duration) {
         *self = *self + rhs;
@@ -1118,7 +1120,8 @@ impl AddAssign for Duration {
 }
 
 #[stable(feature = "duration", since = "1.3.0")]
-impl Sub for Duration {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Sub for Duration {
     type Output = Duration;
 
     #[inline]
@@ -1128,7 +1131,8 @@ impl Sub for Duration {
 }
 
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl SubAssign for Duration {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const SubAssign for Duration {
     #[inline]
     fn sub_assign(&mut self, rhs: Duration) {
         *self = *self - rhs;
@@ -1136,7 +1140,8 @@ impl SubAssign for Duration {
 }
 
 #[stable(feature = "duration", since = "1.3.0")]
-impl Mul<u32> for Duration {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Mul<u32> for Duration {
     type Output = Duration;
 
     #[inline]
@@ -1146,7 +1151,8 @@ impl Mul<u32> for Duration {
 }
 
 #[stable(feature = "symmetric_u32_duration_mul", since = "1.31.0")]
-impl Mul<Duration> for u32 {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Mul<Duration> for u32 {
     type Output = Duration;
 
     #[inline]
@@ -1156,7 +1162,8 @@ impl Mul<Duration> for u32 {
 }
 
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl MulAssign<u32> for Duration {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const MulAssign<u32> for Duration {
     #[inline]
     fn mul_assign(&mut self, rhs: u32) {
         *self = *self * rhs;
@@ -1164,7 +1171,8 @@ impl MulAssign<u32> for Duration {
 }
 
 #[stable(feature = "duration", since = "1.3.0")]
-impl Div<u32> for Duration {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Div<u32> for Duration {
     type Output = Duration;
 
     #[inline]
@@ -1175,7 +1183,8 @@ impl Div<u32> for Duration {
 }
 
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl DivAssign<u32> for Duration {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const DivAssign<u32> for Duration {
     #[inline]
     #[track_caller]
     fn div_assign(&mut self, rhs: u32) {
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index 9b674a25165..09feddd0be9 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -80,7 +80,7 @@ pub struct OpenOptions {
     attributes: u32,
     share_mode: u32,
     security_qos_flags: u32,
-    security_attributes: *mut c::SECURITY_ATTRIBUTES,
+    inherit_handle: bool,
 }
 
 #[derive(Clone, PartialEq, Eq, Debug)]
@@ -203,7 +203,7 @@ impl OpenOptions {
             share_mode: c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
             attributes: 0,
             security_qos_flags: 0,
-            security_attributes: ptr::null_mut(),
+            inherit_handle: false,
         }
     }
 
@@ -243,8 +243,8 @@ impl OpenOptions {
         // receive is `SECURITY_ANONYMOUS = 0x0`, which we can't check for later on.
         self.security_qos_flags = flags | c::SECURITY_SQOS_PRESENT;
     }
-    pub fn security_attributes(&mut self, attrs: *mut c::SECURITY_ATTRIBUTES) {
-        self.security_attributes = attrs;
+    pub fn inherit_handle(&mut self, inherit: bool) {
+        self.inherit_handle = inherit;
     }
 
     fn get_access_mode(&self) -> io::Result<u32> {
@@ -307,12 +307,17 @@ impl File {
 
     fn open_native(path: &WCStr, opts: &OpenOptions) -> io::Result<File> {
         let creation = opts.get_creation_mode()?;
+        let sa = c::SECURITY_ATTRIBUTES {
+            nLength: size_of::<c::SECURITY_ATTRIBUTES>() as u32,
+            lpSecurityDescriptor: ptr::null_mut(),
+            bInheritHandle: opts.inherit_handle as c::BOOL,
+        };
         let handle = unsafe {
             c::CreateFileW(
                 path.as_ptr(),
                 opts.get_access_mode()?,
                 opts.share_mode,
-                opts.security_attributes,
+                if opts.inherit_handle { &sa } else { ptr::null() },
                 creation,
                 opts.get_flags_and_attributes(),
                 ptr::null_mut(),
diff --git a/library/std/src/sys/io/io_slice/uefi.rs b/library/std/src/sys/io/io_slice/uefi.rs
new file mode 100644
index 00000000000..909cfbea0b7
--- /dev/null
+++ b/library/std/src/sys/io/io_slice/uefi.rs
@@ -0,0 +1,74 @@
+//! A buffer type used with `Write::write_vectored` for UEFI Networking APIs. Vectored writing to
+//! File is not supported as of UEFI Spec 2.11.
+
+use crate::marker::PhantomData;
+use crate::slice;
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct IoSlice<'a> {
+    len: u32,
+    data: *const u8,
+    _p: PhantomData<&'a [u8]>,
+}
+
+impl<'a> IoSlice<'a> {
+    #[inline]
+    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
+        let len = buf.len().try_into().unwrap();
+        Self { len, data: buf.as_ptr(), _p: PhantomData }
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        self.len = u32::try_from(n)
+            .ok()
+            .and_then(|n| self.len.checked_sub(n))
+            .expect("advancing IoSlice beyond its length");
+        unsafe { self.data = self.data.add(n) };
+    }
+
+    #[inline]
+    pub const fn as_slice(&self) -> &'a [u8] {
+        unsafe { slice::from_raw_parts(self.data, self.len as usize) }
+    }
+}
+
+#[repr(C)]
+pub struct IoSliceMut<'a> {
+    len: u32,
+    data: *mut u8,
+    _p: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoSliceMut<'a> {
+    #[inline]
+    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
+        let len = buf.len().try_into().unwrap();
+        Self { len, data: buf.as_mut_ptr(), _p: PhantomData }
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        self.len = u32::try_from(n)
+            .ok()
+            .and_then(|n| self.len.checked_sub(n))
+            .expect("advancing IoSlice beyond its length");
+        unsafe { self.data = self.data.add(n) };
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        unsafe { slice::from_raw_parts(self.data, self.len as usize) }
+    }
+
+    #[inline]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
+    }
+
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
+    }
+}
diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs
index 4d0365d42fd..ae75f4d97b4 100644
--- a/library/std/src/sys/io/mod.rs
+++ b/library/std/src/sys/io/mod.rs
@@ -11,6 +11,9 @@ mod io_slice {
         } else if #[cfg(target_os = "wasi")] {
             mod wasi;
             pub use wasi::*;
+        } else if #[cfg(target_os = "uefi")] {
+            mod uefi;
+            pub use uefi::*;
         } else {
             mod unsupported;
             pub use unsupported::*;
diff --git a/library/std/src/sys/pal/uefi/tests.rs b/library/std/src/sys/pal/uefi/tests.rs
index 38658cc4e9a..49e75a1a70d 100644
--- a/library/std/src/sys/pal/uefi/tests.rs
+++ b/library/std/src/sys/pal/uefi/tests.rs
@@ -1,5 +1,6 @@
 use super::alloc::*;
 use super::time::*;
+use crate::io::{IoSlice, IoSliceMut};
 use crate::time::Duration;
 
 #[test]
@@ -39,3 +40,121 @@ fn epoch() {
     };
     assert_eq!(system_time_internal::uefi_time_to_duration(t), Duration::new(0, 0));
 }
+
+// UEFI IoSlice and IoSliceMut Tests
+//
+// Strictly speaking, vectored read/write types for UDP4, UDP6, TCP4, TCP6 are defined
+// separately in the UEFI Spec. However, they have the same signature. These tests just ensure
+// that `IoSlice` and `IoSliceMut` are compatible with the vectored types for all the
+// networking protocols.
+
+unsafe fn to_slice<T>(val: &T) -> &[u8] {
+    let len = size_of_val(val);
+    unsafe { crate::slice::from_raw_parts(crate::ptr::from_ref(val).cast(), len) }
+}
+
+#[test]
+fn io_slice_single() {
+    let mut data = [0, 1, 2, 3, 4];
+
+    let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let tcp6_frag = r_efi::protocols::tcp6::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let udp4_frag = r_efi::protocols::udp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let udp6_frag = r_efi::protocols::udp6::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let io_slice = IoSlice::new(&data);
+
+    unsafe {
+        assert_eq!(to_slice(&io_slice), to_slice(&tcp4_frag));
+        assert_eq!(to_slice(&io_slice), to_slice(&tcp6_frag));
+        assert_eq!(to_slice(&io_slice), to_slice(&udp4_frag));
+        assert_eq!(to_slice(&io_slice), to_slice(&udp6_frag));
+    }
+}
+
+#[test]
+fn io_slice_mut_single() {
+    let mut data = [0, 1, 2, 3, 4];
+
+    let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let tcp6_frag = r_efi::protocols::tcp6::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let udp4_frag = r_efi::protocols::udp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let udp6_frag = r_efi::protocols::udp6::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let io_slice_mut = IoSliceMut::new(&mut data);
+
+    unsafe {
+        assert_eq!(to_slice(&io_slice_mut), to_slice(&tcp4_frag));
+        assert_eq!(to_slice(&io_slice_mut), to_slice(&tcp6_frag));
+        assert_eq!(to_slice(&io_slice_mut), to_slice(&udp4_frag));
+        assert_eq!(to_slice(&io_slice_mut), to_slice(&udp6_frag));
+    }
+}
+
+#[test]
+fn io_slice_multi() {
+    let mut data = [0, 1, 2, 3, 4];
+
+    let tcp4_frag = r_efi::protocols::tcp4::FragmentData {
+        fragment_length: data.len().try_into().unwrap(),
+        fragment_buffer: data.as_mut_ptr().cast(),
+    };
+    let rhs =
+        [tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag.clone(), tcp4_frag];
+    let lhs = [
+        IoSlice::new(&data),
+        IoSlice::new(&data),
+        IoSlice::new(&data),
+        IoSlice::new(&data),
+        IoSlice::new(&data),
+    ];
+
+    unsafe {
+        assert_eq!(to_slice(&lhs), to_slice(&rhs));
+    }
+}
+
+#[test]
+fn io_slice_basic() {
+    let data = [0, 1, 2, 3, 4];
+    let mut io_slice = IoSlice::new(&data);
+
+    assert_eq!(data, io_slice.as_slice());
+    io_slice.advance(2);
+    assert_eq!(&data[2..], io_slice.as_slice());
+}
+
+#[test]
+fn io_slice_mut_basic() {
+    let data = [0, 1, 2, 3, 4];
+    let mut data_clone = [0, 1, 2, 3, 4];
+    let mut io_slice_mut = IoSliceMut::new(&mut data_clone);
+
+    assert_eq!(data, io_slice_mut.as_slice());
+    assert_eq!(data, io_slice_mut.as_mut_slice());
+
+    io_slice_mut.advance(2);
+    assert_eq!(&data[2..], io_slice_mut.into_slice());
+}
diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs
index 1ee3fbd285f..f9e15b82475 100644
--- a/library/std/src/sys/process/windows.rs
+++ b/library/std/src/sys/process/windows.rs
@@ -623,16 +623,10 @@ impl Stdio {
             // permissions as well as the ability to be inherited to child
             // processes (as this is about to be inherited).
             Stdio::Null => {
-                let size = size_of::<c::SECURITY_ATTRIBUTES>();
-                let mut sa = c::SECURITY_ATTRIBUTES {
-                    nLength: size as u32,
-                    lpSecurityDescriptor: ptr::null_mut(),
-                    bInheritHandle: 1,
-                };
                 let mut opts = OpenOptions::new();
                 opts.read(stdio_id == c::STD_INPUT_HANDLE);
                 opts.write(stdio_id != c::STD_INPUT_HANDLE);
-                opts.security_attributes(&mut sa);
+                opts.inherit_handle(true);
                 File::open(Path::new(r"\\.\NUL"), &opts).map(|file| file.into_inner())
             }
         }
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 3fbc8cdbcd5..2c3fb9458ef 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -925,6 +925,8 @@ fn copy_src_dirs(
             "llvm-project\\cmake",
             "llvm-project/runtimes",
             "llvm-project\\runtimes",
+            "llvm-project/third-party",
+            "llvm-project\\third-party",
         ];
         if spath.contains("llvm-project")
             && !spath.ends_with("llvm-project")
@@ -933,6 +935,18 @@ fn copy_src_dirs(
             return false;
         }
 
+        // Keep only these third party libraries
+        const LLVM_THIRD_PARTY: &[&str] =
+            &["llvm-project/third-party/siphash", "llvm-project\\third-party\\siphash"];
+        if (spath.starts_with("llvm-project/third-party")
+            || spath.starts_with("llvm-project\\third-party"))
+            && !(spath.ends_with("llvm-project/third-party")
+                || spath.ends_with("llvm-project\\third-party"))
+            && !LLVM_THIRD_PARTY.iter().any(|path| spath.contains(path))
+        {
+            return false;
+        }
+
         const LLVM_TEST: &[&str] = &["llvm-project/llvm/test", "llvm-project\\llvm\\test"];
         if LLVM_TEST.iter().any(|path| spath.contains(path))
             && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 79244827059..16941a32bb1 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -196,7 +196,10 @@ pub(crate) fn detect_llvm_freshness(config: &Config, is_git: bool) -> PathFreshn
 ///
 /// This checks the build triple platform to confirm we're usable at all, and if LLVM
 /// with/without assertions is available.
-pub(crate) fn is_ci_llvm_available_for_target(config: &Config, asserts: bool) -> bool {
+pub(crate) fn is_ci_llvm_available_for_target(
+    host_target: &TargetSelection,
+    asserts: bool,
+) -> bool {
     // This is currently all tier 1 targets and tier 2 targets with host tools
     // (since others may not have CI artifacts)
     // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
@@ -235,8 +238,8 @@ pub(crate) fn is_ci_llvm_available_for_target(config: &Config, asserts: bool) ->
         ("x86_64-unknown-netbsd", false),
     ];
 
-    if !supported_platforms.contains(&(&*config.host_target.triple, asserts))
-        && (asserts || !supported_platforms.contains(&(&*config.host_target.triple, true)))
+    if !supported_platforms.contains(&(&*host_target.triple, asserts))
+        && (asserts || !supported_platforms.contains(&(&*host_target.triple, true)))
     {
         return false;
     }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index eb1ac8c637f..3eadb1083f4 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -893,21 +893,25 @@ impl Config {
         let default = config.channel == "dev";
         config.omit_git_hash = rust_omit_git_hash.unwrap_or(default);
 
-        config.rust_info = config.git_info(config.omit_git_hash, &config.src);
+        config.rust_info = git_info(&config.exec_ctx, config.omit_git_hash, &config.src);
         config.cargo_info =
-            config.git_info(config.omit_git_hash, &config.src.join("src/tools/cargo"));
-        config.rust_analyzer_info =
-            config.git_info(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer"));
+            git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/cargo"));
+        config.rust_analyzer_info = git_info(
+            &config.exec_ctx,
+            config.omit_git_hash,
+            &config.src.join("src/tools/rust-analyzer"),
+        );
         config.clippy_info =
-            config.git_info(config.omit_git_hash, &config.src.join("src/tools/clippy"));
+            git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/clippy"));
         config.miri_info =
-            config.git_info(config.omit_git_hash, &config.src.join("src/tools/miri"));
+            git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/miri"));
         config.rustfmt_info =
-            config.git_info(config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
+            git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
         config.enzyme_info =
-            config.git_info(config.omit_git_hash, &config.src.join("src/tools/enzyme"));
-        config.in_tree_llvm_info = config.git_info(false, &config.src.join("src/llvm-project"));
-        config.in_tree_gcc_info = config.git_info(false, &config.src.join("src/gcc"));
+            git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/enzyme"));
+        config.in_tree_llvm_info =
+            git_info(&config.exec_ctx, false, &config.src.join("src/llvm-project"));
+        config.in_tree_gcc_info = git_info(&config.exec_ctx, false, &config.src.join("src/gcc"));
 
         config.vendor = build_vendor.unwrap_or(
             config.rust_info.is_from_tarball()
@@ -947,11 +951,18 @@ impl Config {
             );
         }
 
-        config.download_rustc_commit = config.download_ci_rustc_commit(
-            rust_download_rustc,
-            debug_assertions_requested,
-            config.llvm_assertions,
-        );
+        let dwn_ctx = DownloadContext::from(&config);
+        config.download_rustc_commit =
+            download_ci_rustc_commit(dwn_ctx, rust_download_rustc, config.llvm_assertions);
+
+        if debug_assertions_requested {
+            eprintln!(
+                "WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \
+                rustc is not currently built with debug assertions."
+            );
+            // We need to put this later down_ci_rustc_commit.
+            config.download_rustc_commit = None;
+        }
 
         if let Some(t) = toml.target {
             for (triple, cfg) in t {
@@ -1157,8 +1168,9 @@ impl Config {
                 "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
             );
 
+            let dwn_ctx = DownloadContext::from(&config);
             let channel =
-                config.read_file_by_commit(Path::new("src/ci/channel"), commit).trim().to_owned();
+                read_file_by_commit(dwn_ctx, Path::new("src/ci/channel"), commit).trim().to_owned();
 
             config.channel = channel;
         }
@@ -1193,8 +1205,9 @@ impl Config {
         config.llvm_enable_warnings = llvm_enable_warnings.unwrap_or(false);
         config.llvm_build_config = llvm_build_config.clone().unwrap_or(Default::default());
 
+        let dwn_ctx = DownloadContext::from(&config);
         config.llvm_from_ci =
-            config.parse_download_ci_llvm(llvm_download_ci_llvm, config.llvm_assertions);
+            parse_download_ci_llvm(dwn_ctx, llvm_download_ci_llvm, config.llvm_assertions);
 
         if config.llvm_from_ci {
             let warn = |option: &str| {
@@ -1256,7 +1269,8 @@ impl Config {
 
         if config.llvm_from_ci {
             let triple = &config.host_target.triple;
-            let ci_llvm_bin = config.ci_llvm_root().join("bin");
+            let dwn_ctx = DownloadContext::from(&config);
+            let ci_llvm_bin = ci_llvm_root(dwn_ctx).join("bin");
             let build_target = config
                 .target_config
                 .entry(config.host_target)
@@ -1297,7 +1311,8 @@ impl Config {
             );
         }
 
-        if config.lld_enabled && config.is_system_llvm(config.host_target) {
+        let dwn_ctx = DownloadContext::from(&config);
+        if config.lld_enabled && is_system_llvm(dwn_ctx, config.host_target) {
             panic!("Cannot enable LLD with `rust.lld = true` when using external llvm-config.");
         }
 
@@ -1432,14 +1447,8 @@ impl Config {
 
     /// Returns the content of the given file at a specific commit.
     pub(crate) fn read_file_by_commit(&self, file: &Path, commit: &str) -> String {
-        assert!(
-            self.rust_info.is_managed_git_subrepository(),
-            "`Config::read_file_by_commit` is not supported in non-git sources."
-        );
-
-        let mut git = helpers::git(Some(&self.src));
-        git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap()));
-        git.run_capture_stdout(self).stdout()
+        let dwn_ctx = DownloadContext::from(self);
+        read_file_by_commit(dwn_ctx, file, commit)
     }
 
     /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
@@ -1510,8 +1519,8 @@ impl Config {
 
     /// The absolute path to the downloaded LLVM artifacts.
     pub(crate) fn ci_llvm_root(&self) -> PathBuf {
-        assert!(self.llvm_from_ci);
-        self.out.join(self.host_target).join("ci-llvm")
+        let dwn_ctx = DownloadContext::from(self);
+        ci_llvm_root(dwn_ctx)
     }
 
     /// Directory where the extracted `rustc-dev` component is stored.
@@ -1674,261 +1683,14 @@ impl Config {
         ),
     )]
     pub(crate) fn update_submodule(&self, relative_path: &str) {
-        if self.rust_info.is_from_tarball() || !self.submodules() {
-            return;
-        }
-
-        let absolute_path = self.src.join(relative_path);
-
-        // NOTE: This check is required because `jj git clone` doesn't create directories for
-        // submodules, they are completely ignored. The code below assumes this directory exists,
-        // so create it here.
-        if !absolute_path.exists() {
-            t!(fs::create_dir_all(&absolute_path));
-        }
-
-        // NOTE: The check for the empty directory is here because when running x.py the first time,
-        // the submodule won't be checked out. Check it out now so we can build it.
-        if !self.git_info(false, &absolute_path).is_managed_git_subrepository()
-            && !helpers::dir_is_empty(&absolute_path)
-        {
-            return;
-        }
-
-        // Submodule updating actually happens during in the dry run mode. We need to make sure that
-        // all the git commands below are actually executed, because some follow-up code
-        // in bootstrap might depend on the submodules being checked out. Furthermore, not all
-        // the command executions below work with an empty output (produced during dry run).
-        // Therefore, all commands below are marked with `run_in_dry_run()`, so that they also run in
-        // dry run mode.
-        let submodule_git = || {
-            let mut cmd = helpers::git(Some(&absolute_path));
-            cmd.run_in_dry_run();
-            cmd
-        };
-
-        // Determine commit checked out in submodule.
-        let checked_out_hash =
-            submodule_git().args(["rev-parse", "HEAD"]).run_capture_stdout(self).stdout();
-        let checked_out_hash = checked_out_hash.trim_end();
-        // Determine commit that the submodule *should* have.
-        let recorded = helpers::git(Some(&self.src))
-            .run_in_dry_run()
-            .args(["ls-tree", "HEAD"])
-            .arg(relative_path)
-            .run_capture_stdout(self)
-            .stdout();
-
-        let actual_hash = recorded
-            .split_whitespace()
-            .nth(2)
-            .unwrap_or_else(|| panic!("unexpected output `{recorded}`"));
-
-        if actual_hash == checked_out_hash {
-            // already checked out
-            return;
-        }
-
-        println!("Updating submodule {relative_path}");
-
-        helpers::git(Some(&self.src))
-            .allow_failure()
-            .run_in_dry_run()
-            .args(["submodule", "-q", "sync"])
-            .arg(relative_path)
-            .run(self);
-
-        // Try passing `--progress` to start, then run git again without if that fails.
-        let update = |progress: bool| {
-            // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
-            // even though that has no relation to the upstream for the submodule.
-            let current_branch = helpers::git(Some(&self.src))
-                .allow_failure()
-                .run_in_dry_run()
-                .args(["symbolic-ref", "--short", "HEAD"])
-                .run_capture(self);
-
-            let mut git = helpers::git(Some(&self.src)).allow_failure();
-            git.run_in_dry_run();
-            if current_branch.is_success() {
-                // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
-                // This syntax isn't accepted by `branch.{branch}`. Strip it.
-                let branch = current_branch.stdout();
-                let branch = branch.trim();
-                let branch = branch.strip_prefix("heads/").unwrap_or(branch);
-                git.arg("-c").arg(format!("branch.{branch}.remote=origin"));
-            }
-            git.args(["submodule", "update", "--init", "--recursive", "--depth=1"]);
-            if progress {
-                git.arg("--progress");
-            }
-            git.arg(relative_path);
-            git
-        };
-        if !update(true).allow_failure().run(self) {
-            update(false).allow_failure().run(self);
-        }
-
-        // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
-        // diff-index reports the modifications through the exit status
-        let has_local_modifications =
-            !submodule_git().allow_failure().args(["diff-index", "--quiet", "HEAD"]).run(self);
-        if has_local_modifications {
-            submodule_git().allow_failure().args(["stash", "push"]).run(self);
-        }
-
-        submodule_git().allow_failure().args(["reset", "-q", "--hard"]).run(self);
-        submodule_git().allow_failure().args(["clean", "-qdfx"]).run(self);
-
-        if has_local_modifications {
-            submodule_git().allow_failure().args(["stash", "pop"]).run(self);
-        }
-    }
-
-    /// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
-    pub fn download_ci_rustc_commit(
-        &self,
-        download_rustc: Option<StringOrBool>,
-        debug_assertions_requested: bool,
-        llvm_assertions: bool,
-    ) -> Option<String> {
-        if !is_download_ci_available(&self.host_target.triple, llvm_assertions) {
-            return None;
-        }
-
-        // If `download-rustc` is not set, default to rebuilding.
-        let if_unchanged = match download_rustc {
-            // Globally default `download-rustc` to `false`, because some contributors don't use
-            // profiles for reasons such as:
-            // - They need to seamlessly switch between compiler/library work.
-            // - They don't want to use compiler profile because they need to override too many
-            //   things and it's easier to not use a profile.
-            None | Some(StringOrBool::Bool(false)) => return None,
-            Some(StringOrBool::Bool(true)) => false,
-            Some(StringOrBool::String(s)) if s == "if-unchanged" => {
-                if !self.rust_info.is_managed_git_subrepository() {
-                    println!(
-                        "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources."
-                    );
-                    crate::exit!(1);
-                }
-
-                true
-            }
-            Some(StringOrBool::String(other)) => {
-                panic!("unrecognized option for download-rustc: {other}")
-            }
-        };
-
-        let commit = if self.rust_info.is_managed_git_subrepository() {
-            // Look for a version to compare to based on the current commit.
-            // Only commits merged by bors will have CI artifacts.
-            let freshness = self.check_path_modifications(RUSTC_IF_UNCHANGED_ALLOWED_PATHS);
-            self.verbose(|| {
-                eprintln!("rustc freshness: {freshness:?}");
-            });
-            match freshness {
-                PathFreshness::LastModifiedUpstream { upstream } => upstream,
-                PathFreshness::HasLocalModifications { upstream } => {
-                    if if_unchanged {
-                        return None;
-                    }
-
-                    if self.is_running_on_ci {
-                        eprintln!("CI rustc commit matches with HEAD and we are in CI.");
-                        eprintln!(
-                            "`rustc.download-ci` functionality will be skipped as artifacts are not available."
-                        );
-                        return None;
-                    }
-
-                    upstream
-                }
-                PathFreshness::MissingUpstream => {
-                    eprintln!("No upstream commit found");
-                    return None;
-                }
-            }
-        } else {
-            channel::read_commit_info_file(&self.src)
-                .map(|info| info.sha.trim().to_owned())
-                .expect("git-commit-info is missing in the project root")
-        };
-
-        if debug_assertions_requested {
-            eprintln!(
-                "WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \
-                rustc is not currently built with debug assertions."
-            );
-            return None;
-        }
-
-        Some(commit)
-    }
-
-    pub fn parse_download_ci_llvm(
-        &self,
-        download_ci_llvm: Option<StringOrBool>,
-        asserts: bool,
-    ) -> bool {
-        // We don't ever want to use `true` on CI, as we should not
-        // download upstream artifacts if there are any local modifications.
-        let default = if self.is_running_on_ci {
-            StringOrBool::String("if-unchanged".to_string())
-        } else {
-            StringOrBool::Bool(true)
-        };
-        let download_ci_llvm = download_ci_llvm.unwrap_or(default);
-
-        let if_unchanged = || {
-            if self.rust_info.is_from_tarball() {
-                // Git is needed for running "if-unchanged" logic.
-                println!("ERROR: 'if-unchanged' is only compatible with Git managed sources.");
-                crate::exit!(1);
-            }
-
-            // Fetching the LLVM submodule is unnecessary for self-tests.
-            #[cfg(not(test))]
-            self.update_submodule("src/llvm-project");
-
-            // Check for untracked changes in `src/llvm-project` and other important places.
-            let has_changes = self.has_changes_from_upstream(LLVM_INVALIDATION_PATHS);
-
-            // Return false if there are untracked changes, otherwise check if CI LLVM is available.
-            if has_changes { false } else { llvm::is_ci_llvm_available_for_target(self, asserts) }
-        };
-
-        match download_ci_llvm {
-            StringOrBool::Bool(b) => {
-                if !b && self.download_rustc_commit.is_some() {
-                    panic!(
-                        "`llvm.download-ci-llvm` cannot be set to `false` if `rust.download-rustc` is set to `true` or `if-unchanged`."
-                    );
-                }
-
-                if b && self.is_running_on_ci {
-                    // On CI, we must always rebuild LLVM if there were any modifications to it
-                    panic!(
-                        "`llvm.download-ci-llvm` cannot be set to `true` on CI. Use `if-unchanged` instead."
-                    );
-                }
-
-                // If download-ci-llvm=true we also want to check that CI llvm is available
-                b && llvm::is_ci_llvm_available_for_target(self, asserts)
-            }
-            StringOrBool::String(s) if s == "if-unchanged" => if_unchanged(),
-            StringOrBool::String(other) => {
-                panic!("unrecognized option for download-ci-llvm: {other:?}")
-            }
-        }
+        let dwn_ctx = DownloadContext::from(self);
+        update_submodule(dwn_ctx, relative_path);
     }
 
     /// Returns true if any of the `paths` have been modified locally.
     pub fn has_changes_from_upstream(&self, paths: &[&'static str]) -> bool {
-        match self.check_path_modifications(paths) {
-            PathFreshness::LastModifiedUpstream { .. } => false,
-            PathFreshness::HasLocalModifications { .. } | PathFreshness::MissingUpstream => true,
-        }
+        let dwn_ctx = DownloadContext::from(self);
+        has_changes_from_upstream(dwn_ctx, paths)
     }
 
     /// Checks whether any of the given paths have been modified w.r.t. upstream.
@@ -1949,10 +1711,6 @@ impl Config {
             .clone()
     }
 
-    pub fn ci_env(&self) -> CiEnv {
-        if self.is_running_on_ci { CiEnv::GitHubActions } else { CiEnv::None }
-    }
-
     pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
         self.target_config.get(&target).and_then(|t| t.sanitizers).unwrap_or(self.sanitizers)
     }
@@ -2041,15 +1799,8 @@ impl Config {
     ///
     /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set.
     pub fn is_system_llvm(&self, target: TargetSelection) -> bool {
-        match self.target_config.get(&target) {
-            Some(Target { llvm_config: Some(_), .. }) => {
-                let ci_llvm = self.llvm_from_ci && self.is_host_target(target);
-                !ci_llvm
-            }
-            // We're building from the in-tree src/llvm-project sources.
-            Some(Target { llvm_config: None, .. }) => false,
-            None => false,
-        }
+        let dwn_ctx = DownloadContext::from(self);
+        is_system_llvm(dwn_ctx, target)
     }
 
     /// Returns `true` if this is our custom, patched, version of LLVM.
@@ -2340,3 +2091,365 @@ pub fn check_stage0_version(
         ));
     }
 }
+
+pub fn download_ci_rustc_commit<'a>(
+    dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    download_rustc: Option<StringOrBool>,
+    llvm_assertions: bool,
+) -> Option<String> {
+    let dwn_ctx = dwn_ctx.as_ref();
+
+    if !is_download_ci_available(&dwn_ctx.host_target.triple, llvm_assertions) {
+        return None;
+    }
+
+    // If `download-rustc` is not set, default to rebuilding.
+    let if_unchanged = match download_rustc {
+        // Globally default `download-rustc` to `false`, because some contributors don't use
+        // profiles for reasons such as:
+        // - They need to seamlessly switch between compiler/library work.
+        // - They don't want to use compiler profile because they need to override too many
+        //   things and it's easier to not use a profile.
+        None | Some(StringOrBool::Bool(false)) => return None,
+        Some(StringOrBool::Bool(true)) => false,
+        Some(StringOrBool::String(s)) if s == "if-unchanged" => {
+            if !dwn_ctx.rust_info.is_managed_git_subrepository() {
+                println!(
+                    "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources."
+                );
+                crate::exit!(1);
+            }
+
+            true
+        }
+        Some(StringOrBool::String(other)) => {
+            panic!("unrecognized option for download-rustc: {other}")
+        }
+    };
+
+    let commit = if dwn_ctx.rust_info.is_managed_git_subrepository() {
+        // Look for a version to compare to based on the current commit.
+        // Only commits merged by bors will have CI artifacts.
+        let freshness = check_path_modifications_(dwn_ctx, RUSTC_IF_UNCHANGED_ALLOWED_PATHS);
+        dwn_ctx.exec_ctx.verbose(|| {
+            eprintln!("rustc freshness: {freshness:?}");
+        });
+        match freshness {
+            PathFreshness::LastModifiedUpstream { upstream } => upstream,
+            PathFreshness::HasLocalModifications { upstream } => {
+                if if_unchanged {
+                    return None;
+                }
+
+                if dwn_ctx.is_running_on_ci {
+                    eprintln!("CI rustc commit matches with HEAD and we are in CI.");
+                    eprintln!(
+                        "`rustc.download-ci` functionality will be skipped as artifacts are not available."
+                    );
+                    return None;
+                }
+
+                upstream
+            }
+            PathFreshness::MissingUpstream => {
+                eprintln!("No upstream commit found");
+                return None;
+            }
+        }
+    } else {
+        channel::read_commit_info_file(dwn_ctx.src)
+            .map(|info| info.sha.trim().to_owned())
+            .expect("git-commit-info is missing in the project root")
+    };
+
+    Some(commit)
+}
+
+pub fn check_path_modifications_<'a>(
+    dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    paths: &[&'static str],
+) -> PathFreshness {
+    let dwn_ctx = dwn_ctx.as_ref();
+    // Checking path modifications through git can be relatively expensive (>100ms).
+    // We do not assume that the sources would change during bootstrap's execution,
+    // so we can cache the results here.
+    // Note that we do not use a static variable for the cache, because it would cause problems
+    // in tests that create separate `Config` instsances.
+    dwn_ctx
+        .path_modification_cache
+        .lock()
+        .unwrap()
+        .entry(paths.to_vec())
+        .or_insert_with(|| {
+            check_path_modifications(
+                dwn_ctx.src,
+                &git_config(dwn_ctx.stage0_metadata),
+                paths,
+                CiEnv::current(),
+            )
+            .unwrap()
+        })
+        .clone()
+}
+
+pub fn git_config(stage0_metadata: &build_helper::stage0_parser::Stage0) -> GitConfig<'_> {
+    GitConfig {
+        nightly_branch: &stage0_metadata.config.nightly_branch,
+        git_merge_commit_email: &stage0_metadata.config.git_merge_commit_email,
+    }
+}
+
+pub fn parse_download_ci_llvm<'a>(
+    dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    download_ci_llvm: Option<StringOrBool>,
+    asserts: bool,
+) -> bool {
+    let dwn_ctx = dwn_ctx.as_ref();
+
+    // We don't ever want to use `true` on CI, as we should not
+    // download upstream artifacts if there are any local modifications.
+    let default = if dwn_ctx.is_running_on_ci {
+        StringOrBool::String("if-unchanged".to_string())
+    } else {
+        StringOrBool::Bool(true)
+    };
+    let download_ci_llvm = download_ci_llvm.unwrap_or(default);
+
+    let if_unchanged = || {
+        if dwn_ctx.rust_info.is_from_tarball() {
+            // Git is needed for running "if-unchanged" logic.
+            println!("ERROR: 'if-unchanged' is only compatible with Git managed sources.");
+            crate::exit!(1);
+        }
+
+        // Fetching the LLVM submodule is unnecessary for self-tests.
+        #[cfg(not(test))]
+        update_submodule(dwn_ctx, "src/llvm-project");
+
+        // Check for untracked changes in `src/llvm-project` and other important places.
+        let has_changes = has_changes_from_upstream(dwn_ctx, LLVM_INVALIDATION_PATHS);
+
+        // Return false if there are untracked changes, otherwise check if CI LLVM is available.
+        if has_changes {
+            false
+        } else {
+            llvm::is_ci_llvm_available_for_target(&dwn_ctx.host_target, asserts)
+        }
+    };
+
+    match download_ci_llvm {
+        StringOrBool::Bool(b) => {
+            if !b && dwn_ctx.download_rustc_commit.is_some() {
+                panic!(
+                    "`llvm.download-ci-llvm` cannot be set to `false` if `rust.download-rustc` is set to `true` or `if-unchanged`."
+                );
+            }
+
+            if b && dwn_ctx.is_running_on_ci {
+                // On CI, we must always rebuild LLVM if there were any modifications to it
+                panic!(
+                    "`llvm.download-ci-llvm` cannot be set to `true` on CI. Use `if-unchanged` instead."
+                );
+            }
+
+            // If download-ci-llvm=true we also want to check that CI llvm is available
+            b && llvm::is_ci_llvm_available_for_target(&dwn_ctx.host_target, asserts)
+        }
+        StringOrBool::String(s) if s == "if-unchanged" => if_unchanged(),
+        StringOrBool::String(other) => {
+            panic!("unrecognized option for download-ci-llvm: {other:?}")
+        }
+    }
+}
+
+pub fn has_changes_from_upstream<'a>(
+    dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    paths: &[&'static str],
+) -> bool {
+    let dwn_ctx = dwn_ctx.as_ref();
+    match check_path_modifications_(dwn_ctx, paths) {
+        PathFreshness::LastModifiedUpstream { .. } => false,
+        PathFreshness::HasLocalModifications { .. } | PathFreshness::MissingUpstream => true,
+    }
+}
+
+#[cfg_attr(
+    feature = "tracing",
+    instrument(
+        level = "trace",
+        name = "Config::update_submodule",
+        skip_all,
+        fields(relative_path = ?relative_path),
+    ),
+)]
+pub(crate) fn update_submodule<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, relative_path: &str) {
+    let dwn_ctx = dwn_ctx.as_ref();
+    if dwn_ctx.rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, dwn_ctx.rust_info) {
+        return;
+    }
+
+    let absolute_path = dwn_ctx.src.join(relative_path);
+
+    // NOTE: This check is required because `jj git clone` doesn't create directories for
+    // submodules, they are completely ignored. The code below assumes this directory exists,
+    // so create it here.
+    if !absolute_path.exists() {
+        t!(fs::create_dir_all(&absolute_path));
+    }
+
+    // NOTE: The check for the empty directory is here because when running x.py the first time,
+    // the submodule won't be checked out. Check it out now so we can build it.
+    if !git_info(dwn_ctx.exec_ctx, false, &absolute_path).is_managed_git_subrepository()
+        && !helpers::dir_is_empty(&absolute_path)
+    {
+        return;
+    }
+
+    // Submodule updating actually happens during in the dry run mode. We need to make sure that
+    // all the git commands below are actually executed, because some follow-up code
+    // in bootstrap might depend on the submodules being checked out. Furthermore, not all
+    // the command executions below work with an empty output (produced during dry run).
+    // Therefore, all commands below are marked with `run_in_dry_run()`, so that they also run in
+    // dry run mode.
+    let submodule_git = || {
+        let mut cmd = helpers::git(Some(&absolute_path));
+        cmd.run_in_dry_run();
+        cmd
+    };
+
+    // Determine commit checked out in submodule.
+    let checked_out_hash =
+        submodule_git().args(["rev-parse", "HEAD"]).run_capture_stdout(dwn_ctx.exec_ctx).stdout();
+    let checked_out_hash = checked_out_hash.trim_end();
+    // Determine commit that the submodule *should* have.
+    let recorded = helpers::git(Some(dwn_ctx.src))
+        .run_in_dry_run()
+        .args(["ls-tree", "HEAD"])
+        .arg(relative_path)
+        .run_capture_stdout(dwn_ctx.exec_ctx)
+        .stdout();
+
+    let actual_hash = recorded
+        .split_whitespace()
+        .nth(2)
+        .unwrap_or_else(|| panic!("unexpected output `{recorded}`"));
+
+    if actual_hash == checked_out_hash {
+        // already checked out
+        return;
+    }
+
+    println!("Updating submodule {relative_path}");
+
+    helpers::git(Some(dwn_ctx.src))
+        .allow_failure()
+        .run_in_dry_run()
+        .args(["submodule", "-q", "sync"])
+        .arg(relative_path)
+        .run(dwn_ctx.exec_ctx);
+
+    // Try passing `--progress` to start, then run git again without if that fails.
+    let update = |progress: bool| {
+        // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
+        // even though that has no relation to the upstream for the submodule.
+        let current_branch = helpers::git(Some(dwn_ctx.src))
+            .allow_failure()
+            .run_in_dry_run()
+            .args(["symbolic-ref", "--short", "HEAD"])
+            .run_capture(dwn_ctx.exec_ctx);
+
+        let mut git = helpers::git(Some(dwn_ctx.src)).allow_failure();
+        git.run_in_dry_run();
+        if current_branch.is_success() {
+            // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
+            // This syntax isn't accepted by `branch.{branch}`. Strip it.
+            let branch = current_branch.stdout();
+            let branch = branch.trim();
+            let branch = branch.strip_prefix("heads/").unwrap_or(branch);
+            git.arg("-c").arg(format!("branch.{branch}.remote=origin"));
+        }
+        git.args(["submodule", "update", "--init", "--recursive", "--depth=1"]);
+        if progress {
+            git.arg("--progress");
+        }
+        git.arg(relative_path);
+        git
+    };
+    if !update(true).allow_failure().run(dwn_ctx.exec_ctx) {
+        update(false).allow_failure().run(dwn_ctx.exec_ctx);
+    }
+
+    // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
+    // diff-index reports the modifications through the exit status
+    let has_local_modifications = !submodule_git()
+        .allow_failure()
+        .args(["diff-index", "--quiet", "HEAD"])
+        .run(dwn_ctx.exec_ctx);
+    if has_local_modifications {
+        submodule_git().allow_failure().args(["stash", "push"]).run(dwn_ctx.exec_ctx);
+    }
+
+    submodule_git().allow_failure().args(["reset", "-q", "--hard"]).run(dwn_ctx.exec_ctx);
+    submodule_git().allow_failure().args(["clean", "-qdfx"]).run(dwn_ctx.exec_ctx);
+
+    if has_local_modifications {
+        submodule_git().allow_failure().args(["stash", "pop"]).run(dwn_ctx.exec_ctx);
+    }
+}
+
+pub fn git_info(exec_ctx: &ExecutionContext, omit_git_hash: bool, dir: &Path) -> GitInfo {
+    GitInfo::new(omit_git_hash, dir, exec_ctx)
+}
+
+pub fn submodules_(submodules: &Option<bool>, rust_info: &channel::GitInfo) -> bool {
+    // If not specified in config, the default is to only manage
+    // submodules if we're currently inside a git repository.
+    submodules.unwrap_or(rust_info.is_managed_git_subrepository())
+}
+
+/// Returns `true` if this is an external version of LLVM not managed by bootstrap.
+/// In particular, we expect llvm sources to be available when this is false.
+///
+/// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set.
+pub fn is_system_llvm<'a>(
+    dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    target: TargetSelection,
+) -> bool {
+    let dwn_ctx = dwn_ctx.as_ref();
+    match dwn_ctx.target_config.get(&target) {
+        Some(Target { llvm_config: Some(_), .. }) => {
+            let ci_llvm = dwn_ctx.llvm_from_ci && is_host_target(&dwn_ctx.host_target, &target);
+            !ci_llvm
+        }
+        // We're building from the in-tree src/llvm-project sources.
+        Some(Target { llvm_config: None, .. }) => false,
+        None => false,
+    }
+}
+
+pub fn is_host_target(host_target: &TargetSelection, target: &TargetSelection) -> bool {
+    host_target == target
+}
+
+pub(crate) fn ci_llvm_root<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) -> PathBuf {
+    let dwn_ctx = dwn_ctx.as_ref();
+    assert!(dwn_ctx.llvm_from_ci);
+    dwn_ctx.out.join(dwn_ctx.host_target).join("ci-llvm")
+}
+
+/// Returns the content of the given file at a specific commit.
+pub(crate) fn read_file_by_commit<'a>(
+    dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    file: &Path,
+    commit: &str,
+) -> String {
+    let dwn_ctx = dwn_ctx.as_ref();
+    assert!(
+        dwn_ctx.rust_info.is_managed_git_subrepository(),
+        "`Config::read_file_by_commit` is not supported in non-git sources."
+    );
+
+    let mut git = helpers::git(Some(dwn_ctx.src));
+    git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap()));
+    git.run_capture_stdout(dwn_ctx.exec_ctx).stdout()
+}
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 7ec6c62a07d..5ded44cef14 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -1,14 +1,17 @@
+use std::collections::HashMap;
 use std::env;
 use std::ffi::OsString;
 use std::fs::{self, File};
 use std::io::{BufRead, BufReader, BufWriter, ErrorKind, Write};
 use std::path::{Path, PathBuf};
-use std::sync::OnceLock;
+use std::sync::{Arc, Mutex, OnceLock};
 
+use build_helper::git::PathFreshness;
 use xz2::bufread::XzDecoder;
 
-use crate::core::config::{BUILDER_CONFIG_FILENAME, TargetSelection};
+use crate::core::config::{BUILDER_CONFIG_FILENAME, Target, TargetSelection};
 use crate::utils::build_stamp::BuildStamp;
+use crate::utils::channel;
 use crate::utils::exec::{ExecutionContext, command};
 use crate::utils::helpers::{exe, hex_encode, move_file};
 use crate::{Config, t};
@@ -398,14 +401,21 @@ impl Config {
 
 /// Only should be used for pre config initialization downloads.
 pub(crate) struct DownloadContext<'a> {
-    host_target: TargetSelection,
-    out: &'a Path,
-    patch_binaries_for_nix: Option<bool>,
-    exec_ctx: &'a ExecutionContext,
-    stage0_metadata: &'a build_helper::stage0_parser::Stage0,
-    llvm_assertions: bool,
-    bootstrap_cache_path: &'a Option<PathBuf>,
-    is_running_on_ci: bool,
+    pub path_modification_cache: Arc<Mutex<HashMap<Vec<&'static str>, PathFreshness>>>,
+    pub src: &'a Path,
+    pub rust_info: &'a channel::GitInfo,
+    pub submodules: &'a Option<bool>,
+    pub download_rustc_commit: &'a Option<String>,
+    pub host_target: TargetSelection,
+    pub llvm_from_ci: bool,
+    pub target_config: &'a HashMap<TargetSelection, Target>,
+    pub out: &'a Path,
+    pub patch_binaries_for_nix: Option<bool>,
+    pub exec_ctx: &'a ExecutionContext,
+    pub stage0_metadata: &'a build_helper::stage0_parser::Stage0,
+    pub llvm_assertions: bool,
+    pub bootstrap_cache_path: &'a Option<PathBuf>,
+    pub is_running_on_ci: bool,
 }
 
 impl<'a> AsRef<DownloadContext<'a>> for DownloadContext<'a> {
@@ -417,7 +427,14 @@ impl<'a> AsRef<DownloadContext<'a>> for DownloadContext<'a> {
 impl<'a> From<&'a Config> for DownloadContext<'a> {
     fn from(value: &'a Config) -> Self {
         DownloadContext {
+            path_modification_cache: value.path_modification_cache.clone(),
+            src: &value.src,
             host_target: value.host_target,
+            rust_info: &value.rust_info,
+            download_rustc_commit: &value.download_rustc_commit,
+            submodules: &value.submodules,
+            llvm_from_ci: value.llvm_from_ci,
+            target_config: &value.target_config,
             out: &value.out,
             patch_binaries_for_nix: value.patch_binaries_for_nix,
             exec_ctx: &value.exec_ctx,
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 9c6141d8222..7317c62df7f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::qualify_min_const_fn::is_stable_const_fn;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::for_each_expr_without_closures;
@@ -21,7 +20,7 @@ pub(super) fn check<'tcx>(
     expr: &'tcx hir::Expr<'_>,
     assignee: &'tcx hir::Expr<'_>,
     e: &'tcx hir::Expr<'_>,
-    msrv: Msrv,
+    _msrv: Msrv,
 ) {
     if let hir::ExprKind::Binary(op, l, r) = &e.kind {
         let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
@@ -45,10 +44,8 @@ pub(super) fn check<'tcx>(
                 }
 
                 // Skip if the trait is not stable in const contexts
-                if is_in_const_context(cx)
-                    && let Some(binop_id) = cx.tcx.associated_item_def_ids(trait_id).first()
-                    && !is_stable_const_fn(cx, *binop_id, msrv)
-                {
+                // FIXME: reintroduce a better check after this is merged back into Clippy
+                if is_in_const_context(cx) {
                     return;
                 }
 
diff --git a/tests/codegen-llvm/issues/saturating-sub-index-139759.rs b/tests/codegen-llvm/issues/saturating-sub-index-139759.rs
new file mode 100644
index 00000000000..eac2f4d306b
--- /dev/null
+++ b/tests/codegen-llvm/issues/saturating-sub-index-139759.rs
@@ -0,0 +1,19 @@
+// Test that calculating an index with saturating subtraction from an in-bounds
+// index doesn't generate another bounds check.
+
+//@ compile-flags: -Copt-level=3
+//@ min-llvm-version: 21
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @bounds_check_is_elided
+#[no_mangle]
+pub fn bounds_check_is_elided(s: &[i32], index: usize) -> i32 {
+    // CHECK-NOT: panic_bounds_check
+    if index < s.len() {
+        let lower_bound = index.saturating_sub(1);
+        s[lower_bound]
+    } else {
+        -1
+    }
+}
diff --git a/tests/ui/issues/issue-23442.rs b/tests/ui/associated-types/unioned-keys-with-associated-type-23442.rs
index 883c5bb511a..89a2d0177a3 100644
--- a/tests/ui/issues/issue-23442.rs
+++ b/tests/ui/associated-types/unioned-keys-with-associated-type-23442.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/23442
 //@ check-pass
 #![allow(dead_code)]
 use std::marker::PhantomData;
diff --git a/tests/ui/attributes/lint_on_root.stderr b/tests/ui/attributes/lint_on_root.stderr
index aaa46e6f54b..aa0645b6194 100644
--- a/tests/ui/attributes/lint_on_root.stderr
+++ b/tests/ui/attributes/lint_on_root.stderr
@@ -10,3 +10,14 @@ LL | #![inline = ""]
 
 error: aborting due to 1 previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+  --> $DIR/lint_on_root.rs:3:1
+   |
+LL | #![inline = ""]
+   | ^^^^^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index e8ae4715398..dd9dd3a6ce7 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -660,3 +660,69 @@ error: aborting due to 74 previous errors; 3 warnings emitted
 
 Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805.
 For more information about an error, try `rustc --explain E0308`.
+Future incompatibility report: Future breakage diagnostic:
+error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+  --> $DIR/malformed-attrs.rs:40:1
+   |
+LL | #[doc]
+   | ^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+  --> $DIR/malformed-attrs.rs:73:1
+   |
+LL | #[doc]
+   | ^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+  --> $DIR/malformed-attrs.rs:80:1
+   |
+LL | #[link]
+   | ^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+  --> $DIR/malformed-attrs.rs:50:1
+   |
+LL | #[inline = 5]
+   | ^^^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
+  --> $DIR/malformed-attrs.rs:91:1
+   |
+LL | #[ignore()]
+   | ^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
+  --> $DIR/malformed-attrs.rs:220:1
+   |
+LL | #[ignore = 1]
+   | ^^^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
diff --git a/tests/ui/issues/issue-91489.rs b/tests/ui/autoref-autoderef/auto-deref-on-cow-regression-91489.rs
index 0566302c481..929e98ad719 100644
--- a/tests/ui/issues/issue-91489.rs
+++ b/tests/ui/autoref-autoderef/auto-deref-on-cow-regression-91489.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/91489
 //@ check-pass
 
 // regression test for #91489
diff --git a/tests/ui/issues/issue-9725.rs b/tests/ui/binding/struct-destructuring-repeated-bindings-9725.rs
index 360effbd119..6b0b8e37b8c 100644
--- a/tests/ui/issues/issue-9725.rs
+++ b/tests/ui/binding/struct-destructuring-repeated-bindings-9725.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9725
 struct A { foo: isize }
 
 fn main() {
diff --git a/tests/ui/issues/issue-9725.stderr b/tests/ui/binding/struct-destructuring-repeated-bindings-9725.stderr
index 687e0cc0f3e..f4d19bed419 100644
--- a/tests/ui/issues/issue-9725.stderr
+++ b/tests/ui/binding/struct-destructuring-repeated-bindings-9725.stderr
@@ -1,11 +1,11 @@
 error[E0416]: identifier `foo` is bound more than once in the same pattern
-  --> $DIR/issue-9725.rs:4:18
+  --> $DIR/struct-destructuring-repeated-bindings-9725.rs:5:18
    |
 LL |     let A { foo, foo } = A { foo: 3 };
    |                  ^^^ used in a pattern more than once
 
 error[E0025]: field `foo` bound multiple times in the pattern
-  --> $DIR/issue-9725.rs:4:18
+  --> $DIR/struct-destructuring-repeated-bindings-9725.rs:5:18
    |
 LL |     let A { foo, foo } = A { foo: 3 };
    |             ---  ^^^ multiple uses of `foo` in pattern
diff --git a/tests/ui/borrowck/borrowck-in-static.stderr b/tests/ui/borrowck/borrowck-in-static.stderr
index 9bcf64dd62e..d85f6f5fdd5 100644
--- a/tests/ui/borrowck/borrowck-in-static.stderr
+++ b/tests/ui/borrowck/borrowck-in-static.stderr
@@ -10,6 +10,7 @@ LL |     Box::new(|| x)
    |              |
    |              captured by this `Fn` closure
    |
+   = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
 help: consider cloning the value if the performance cost is acceptable
    |
 LL |     Box::new(|| x.clone())
diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr
index 732af1593d6..e9e05440766 100644
--- a/tests/ui/borrowck/borrowck-move-by-capture.stderr
+++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr
@@ -12,6 +12,11 @@ LL |         let _h = to_fn_once(move || -> isize { *bar });
    |                             |
    |                             `bar` is moved here
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/borrowck-move-by-capture.rs:3:37
+   |
+LL | fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
+   |                                     ^^^^^^^^
 help: consider cloning the value before moving it into the closure
    |
 LL ~         let value = bar.clone();
diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr
index af65deb16dc..ef022808886 100644
--- a/tests/ui/borrowck/issue-103624.stderr
+++ b/tests/ui/borrowck/issue-103624.stderr
@@ -13,6 +13,11 @@ LL |
 LL |             self.b;
    |             ^^^^^^ `self.b` is moved here
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/issue-103624.rs:7:36
+   |
+LL | async fn spawn_blocking<T>(f: impl (Fn() -> T) + Send + Sync + 'static) -> T {
+   |                                    ^^^^^^^^^^^
 note: if `StructB` implemented `Clone`, you could clone the value
   --> $DIR/issue-103624.rs:23:1
    |
diff --git a/tests/ui/borrowck/issue-87456-point-to-closure.stderr b/tests/ui/borrowck/issue-87456-point-to-closure.stderr
index a0c7cac2add..043e336cd86 100644
--- a/tests/ui/borrowck/issue-87456-point-to-closure.stderr
+++ b/tests/ui/borrowck/issue-87456-point-to-closure.stderr
@@ -10,6 +10,11 @@ LL |
 LL |         let _foo: String = val;
    |                            ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/issue-87456-point-to-closure.rs:3:24
+   |
+LL | fn take_mut(_val: impl FnMut()) {}
+   |                        ^^^^^^^
 help: consider borrowing here
    |
 LL |         let _foo: String = &val;
diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
index 177e9c8d248..d3333041310 100644
--- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
+++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
@@ -10,6 +10,11 @@ LL |         y.into_iter();
    |         |
    |         move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:5:28
+   |
+LL | fn call<F>(f: F) where F : Fn() {
+   |                            ^^^^
 note: `into_iter` takes ownership of the receiver `self`, which moves `y`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
 help: you can `clone` the value and consume it, but this might not be your desired behavior
diff --git a/tests/ui/issues/issue-9942.rs b/tests/ui/cast/constant-expression-cast-9942.rs
index 6332d9b3e08..d0a6f27b7e3 100644
--- a/tests/ui/issues/issue-9942.rs
+++ b/tests/ui/cast/constant-expression-cast-9942.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9942
 //@ run-pass
 
 pub fn main() {
diff --git a/tests/ui/issues/issue-9129.rs b/tests/ui/closures/closure-type-inference-in-context-9129.rs
index 3856cd133e8..53ee8faab85 100644
--- a/tests/ui/issues/issue-9129.rs
+++ b/tests/ui/closures/closure-type-inference-in-context-9129.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9129
 //@ run-pass
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
diff --git a/tests/ui/issues/issue-9951.rs b/tests/ui/coercion/trait-object-coercion-distribution-9951.rs
index 2cd7cd4f430..526d6561510 100644
--- a/tests/ui/issues/issue-9951.rs
+++ b/tests/ui/coercion/trait-object-coercion-distribution-9951.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9951
 //@ run-pass
 
 #![allow(unused_variables)]
diff --git a/tests/ui/issues/issue-9951.stderr b/tests/ui/coercion/trait-object-coercion-distribution-9951.stderr
index 62ed9f3e0cc..0c672aa9b33 100644
--- a/tests/ui/issues/issue-9951.stderr
+++ b/tests/ui/coercion/trait-object-coercion-distribution-9951.stderr
@@ -1,5 +1,5 @@
 warning: method `noop` is never used
-  --> $DIR/issue-9951.rs:6:6
+  --> $DIR/trait-object-coercion-distribution-9951.rs:7:6
    |
 LL | trait Bar {
    |       --- method in this trait
diff --git a/tests/ui/issues/issue-98299.rs b/tests/ui/const-generics/try-from-with-const-genericsrs-98299.rs
index ba63d963475..49c88856bc9 100644
--- a/tests/ui/issues/issue-98299.rs
+++ b/tests/ui/const-generics/try-from-with-const-genericsrs-98299.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/98299
 use std::convert::TryFrom;
 
 pub fn test_usage(p: ()) {
diff --git a/tests/ui/issues/issue-98299.stderr b/tests/ui/const-generics/try-from-with-const-genericsrs-98299.stderr
index b645267e3b9..1557b83b00e 100644
--- a/tests/ui/issues/issue-98299.stderr
+++ b/tests/ui/const-generics/try-from-with-const-genericsrs-98299.stderr
@@ -1,5 +1,5 @@
 error[E0284]: type annotations needed for `SmallCString<_>`
-  --> $DIR/issue-98299.rs:4:36
+  --> $DIR/try-from-with-const-genericsrs-98299.rs:5:36
    |
 LL |     SmallCString::try_from(p).map(|cstr| cstr);
    |     ------------                   ^^^^
@@ -7,7 +7,7 @@ LL |     SmallCString::try_from(p).map(|cstr| cstr);
    |     type must be known at this point
    |
 note: required by a const generic parameter in `SmallCString`
-  --> $DIR/issue-98299.rs:10:25
+  --> $DIR/try-from-with-const-genericsrs-98299.rs:11:25
    |
 LL | pub struct SmallCString<const N: usize> {}
    |                         ^^^^^^^^^^^^^^ required by this const generic parameter in `SmallCString`
@@ -17,7 +17,7 @@ LL |     SmallCString::try_from(p).map(|cstr: SmallCString<N>| cstr);
    |                                        +++++++++++++++++
 
 error[E0284]: type annotations needed for `SmallCString<_>`
-  --> $DIR/issue-98299.rs:4:36
+  --> $DIR/try-from-with-const-genericsrs-98299.rs:5:36
    |
 LL |     SmallCString::try_from(p).map(|cstr| cstr);
    |     ------------                   ^^^^
@@ -25,7 +25,7 @@ LL |     SmallCString::try_from(p).map(|cstr| cstr);
    |     type must be known at this point
    |
 note: required for `SmallCString<_>` to implement `TryFrom<()>`
-  --> $DIR/issue-98299.rs:12:22
+  --> $DIR/try-from-with-const-genericsrs-98299.rs:13:22
    |
 LL | impl<const N: usize> TryFrom<()> for SmallCString<N> {
    |      --------------  ^^^^^^^^^^^     ^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL |     SmallCString::try_from(p).map(|cstr: SmallCString<N>| cstr);
    |                                        +++++++++++++++++
 
 error[E0284]: type annotations needed for `SmallCString<_>`
-  --> $DIR/issue-98299.rs:4:36
+  --> $DIR/try-from-with-const-genericsrs-98299.rs:5:36
    |
 LL |     SmallCString::try_from(p).map(|cstr| cstr);
    |     -------------------------      ^^^^
@@ -45,7 +45,7 @@ LL |     SmallCString::try_from(p).map(|cstr| cstr);
    |     type must be known at this point
    |
 note: required for `SmallCString<_>` to implement `TryFrom<()>`
-  --> $DIR/issue-98299.rs:12:22
+  --> $DIR/try-from-with-const-genericsrs-98299.rs:13:22
    |
 LL | impl<const N: usize> TryFrom<()> for SmallCString<N> {
    |      --------------  ^^^^^^^^^^^     ^^^^^^^^^^^^^^^
diff --git a/tests/ui/issues/auxiliary/issue-9155.rs b/tests/ui/cross-crate/auxiliary/aux-9155.rs
index 049a96a655a..049a96a655a 100644
--- a/tests/ui/issues/auxiliary/issue-9155.rs
+++ b/tests/ui/cross-crate/auxiliary/aux-9155.rs
diff --git a/tests/ui/issues/auxiliary/issue-9906.rs b/tests/ui/cross-crate/auxiliary/aux-9906.rs
index 8a3eea790a2..8a3eea790a2 100644
--- a/tests/ui/issues/auxiliary/issue-9906.rs
+++ b/tests/ui/cross-crate/auxiliary/aux-9906.rs
diff --git a/tests/ui/cross-crate/generic-newtypes-cross-crate-usage-9155.rs b/tests/ui/cross-crate/generic-newtypes-cross-crate-usage-9155.rs
new file mode 100644
index 00000000000..35286615980
--- /dev/null
+++ b/tests/ui/cross-crate/generic-newtypes-cross-crate-usage-9155.rs
@@ -0,0 +1,11 @@
+// https://github.com/rust-lang/rust/issues/9155
+//@ run-pass
+//@ aux-build:aux-9155.rs
+
+extern crate aux_9155;
+
+struct Baz;
+
+pub fn main() {
+    aux_9155::Foo::new(Baz);
+}
diff --git a/tests/ui/cross-crate/reexported-structs-impls-link-error-9906.rs b/tests/ui/cross-crate/reexported-structs-impls-link-error-9906.rs
new file mode 100644
index 00000000000..b49951bd1f9
--- /dev/null
+++ b/tests/ui/cross-crate/reexported-structs-impls-link-error-9906.rs
@@ -0,0 +1,10 @@
+// https://github.com/rust-lang/rust/issues/9906
+//@ run-pass
+//@ aux-build:aux-9906.rs
+
+extern crate aux_9906 as testmod;
+
+pub fn main() {
+    testmod::foo();
+    testmod::FooBar::new(1);
+}
diff --git a/tests/ui/issues/issue-22992.rs b/tests/ui/deref/dereferenceable-type-behavior-22992.rs
index 3bc15cc948a..19fc2e7eb0b 100644
--- a/tests/ui/issues/issue-22992.rs
+++ b/tests/ui/deref/dereferenceable-type-behavior-22992.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/22992
 //@ run-pass
 
 struct X { val: i32 }
@@ -6,7 +7,6 @@ impl std::ops::Deref for X {
     fn deref(&self) -> &i32 { &self.val }
 }
 
-
 trait            M                   { fn m(self); }
 impl             M for i32           { fn m(self) { println!("i32::m()"); } }
 impl             M for X             { fn m(self) { println!("X::m()"); } }
diff --git a/tests/ui/issues/issue-25549-multiple-drop.rs b/tests/ui/drop/multiple-drop-safe-code-25549.rs
index 1eec15a4aa2..dcf7a3fc79c 100644
--- a/tests/ui/issues/issue-25549-multiple-drop.rs
+++ b/tests/ui/drop/multiple-drop-safe-code-25549.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/25549
 //@ run-pass
 #![allow(unused_variables)]
 struct Foo<'r>(&'r mut i32);
diff --git a/tests/ui/issues/issue-9243.rs b/tests/ui/drop/static-variable-with-drop-trait-9243.rs
index 34ae944d1d8..0ae32c983e9 100644
--- a/tests/ui/issues/issue-9243.rs
+++ b/tests/ui/drop/static-variable-with-drop-trait-9243.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9243
 //@ build-pass
 #![allow(dead_code)]
 // Regression test for issue 9243
diff --git a/tests/ui/issues/issue-53333.rs b/tests/ui/editions/edition-specific-identifier-shadowing-53333.rs
index 468b7d8075f..dd973bb8439 100644
--- a/tests/ui/issues/issue-53333.rs
+++ b/tests/ui/editions/edition-specific-identifier-shadowing-53333.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/53333
 //@ run-pass
 #![allow(unused_imports)]
 //@ edition:2018
diff --git a/tests/ui/issues/issue-9837.rs b/tests/ui/enum-discriminant/enum-discriminant-const-eval-truncation-9837.rs
index 33152a5d077..8768d81b93f 100644
--- a/tests/ui/issues/issue-9837.rs
+++ b/tests/ui/enum-discriminant/enum-discriminant-const-eval-truncation-9837.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9837
 //@ run-pass
 const C1: i32 = 0x12345678;
 const C2: isize = C1 as i16 as isize;
diff --git a/tests/ui/issues/issue-9814.rs b/tests/ui/enum/single-variant-enum-deref-error-9814.rs
index a87478e221b..f10d665299c 100644
--- a/tests/ui/issues/issue-9814.rs
+++ b/tests/ui/enum/single-variant-enum-deref-error-9814.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9814
 // Verify that single-variant enums can't be de-referenced
 // Regression test for issue #9814
 
diff --git a/tests/ui/issues/issue-9814.stderr b/tests/ui/enum/single-variant-enum-deref-error-9814.stderr
index fa23fb7c176..5e069f4c21d 100644
--- a/tests/ui/issues/issue-9814.stderr
+++ b/tests/ui/enum/single-variant-enum-deref-error-9814.stderr
@@ -1,5 +1,5 @@
 error[E0614]: type `Foo` cannot be dereferenced
-  --> $DIR/issue-9814.rs:7:13
+  --> $DIR/single-variant-enum-deref-error-9814.rs:8:13
    |
 LL |     let _ = *Foo::Bar(2);
    |             ^^^^^^^^^^^^ can't be dereferenced
diff --git a/tests/ui/issues/issue-3037.rs b/tests/ui/enum/zero-variant-enum-pattern-matching-3037.rs
index 933b450ac8e..7a7abb1c67c 100644
--- a/tests/ui/issues/issue-3037.rs
+++ b/tests/ui/enum/zero-variant-enum-pattern-matching-3037.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/3037
 //@ run-pass
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 4cba54bf67c..324f7e9fd8a 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -318,3 +318,14 @@ error: aborting due to 38 previous errors
 
 Some errors have detailed explanations: E0517, E0518, E0658.
 For more information about an error, try `rustc --explain E0517`.
+Future incompatibility report: Future breakage diagnostic:
+error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
+   |
+LL |     #[inline = "2100"] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
diff --git a/tests/ui/issues/auxiliary/issue-9968.rs b/tests/ui/imports/auxiliary/aux-9968.rs
index 8d795b59ea8..8d795b59ea8 100644
--- a/tests/ui/issues/auxiliary/issue-9968.rs
+++ b/tests/ui/imports/auxiliary/aux-9968.rs
diff --git a/tests/ui/imports/pub-use-link-errors-9968.rs b/tests/ui/imports/pub-use-link-errors-9968.rs
new file mode 100644
index 00000000000..517a0049ce0
--- /dev/null
+++ b/tests/ui/imports/pub-use-link-errors-9968.rs
@@ -0,0 +1,12 @@
+// https://github.com/rust-lang/rust/issues/9968
+//@ run-pass
+//@ aux-build:aux-9968.rs
+
+extern crate aux_9968 as lib;
+
+use lib::{Trait, Struct};
+
+pub fn main()
+{
+    Struct::init().test();
+}
diff --git a/tests/ui/issues/issue-4335.stderr b/tests/ui/issues/issue-4335.stderr
index 42ac6322564..b6d8f086163 100644
--- a/tests/ui/issues/issue-4335.stderr
+++ b/tests/ui/issues/issue-4335.stderr
@@ -10,6 +10,7 @@ LL |     id(Box::new(|| *v))
    |                 |
    |                 captured by this `FnMut` closure
    |
+   = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
 help: if `T` implemented `Clone`, you could clone the value
   --> $DIR/issue-4335.rs:5:10
    |
diff --git a/tests/ui/issues/issue-9155.rs b/tests/ui/issues/issue-9155.rs
deleted file mode 100644
index dfd9dea2009..00000000000
--- a/tests/ui/issues/issue-9155.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ run-pass
-//@ aux-build:issue-9155.rs
-
-
-extern crate issue_9155;
-
-struct Baz;
-
-pub fn main() {
-    issue_9155::Foo::new(Baz);
-}
diff --git a/tests/ui/issues/issue-9906.rs b/tests/ui/issues/issue-9906.rs
deleted file mode 100644
index 50417d3e456..00000000000
--- a/tests/ui/issues/issue-9906.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-//@ aux-build:issue-9906.rs
-
-
-extern crate issue_9906 as testmod;
-
-pub fn main() {
-    testmod::foo();
-    testmod::FooBar::new(1);
-}
diff --git a/tests/ui/issues/issue-9968.rs b/tests/ui/issues/issue-9968.rs
deleted file mode 100644
index 89e60ba5ac7..00000000000
--- a/tests/ui/issues/issue-9968.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ run-pass
-//@ aux-build:issue-9968.rs
-
-
-extern crate issue_9968 as lib;
-
-use lib::{Trait, Struct};
-
-pub fn main()
-{
-    Struct::init().test();
-}
diff --git a/tests/ui/issues/issue-21655.rs b/tests/ui/iterators/for-loop-over-mut-iterator-21655.rs
index 1068b28b338..b5c9826bd45 100644
--- a/tests/ui/issues/issue-21655.rs
+++ b/tests/ui/iterators/for-loop-over-mut-iterator-21655.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/21655
 //@ run-pass
 
 fn test(it: &mut dyn Iterator<Item=i32>) {
diff --git a/tests/ui/issues/issue-9259.rs b/tests/ui/lifetimes/struct-with-lifetime-parameters-9259.rs
index c45288f7d65..7e39fdc3f10 100644
--- a/tests/ui/issues/issue-9259.rs
+++ b/tests/ui/lifetimes/struct-with-lifetime-parameters-9259.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9259
 //@ run-pass
 #![allow(dead_code)]
 
diff --git a/tests/ui/link-native-libs/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr
index 24ad9d825f8..c69899275d5 100644
--- a/tests/ui/link-native-libs/link-attr-validation-early.stderr
+++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr
@@ -19,3 +19,25 @@ LL | #[link = "foo"]
 
 error: aborting due to 2 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+  --> $DIR/link-attr-validation-early.rs:2:1
+   |
+LL | #[link]
+   | ^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+  --> $DIR/link-attr-validation-early.rs:4:1
+   |
+LL | #[link = "foo"]
+   | ^^^^^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
diff --git a/tests/ui/issues/issue-29710.rs b/tests/ui/lint/unused-results-lint-triggered-by-derive-debug-29710.rs
index 906ffe9e77b..51702f69c20 100644
--- a/tests/ui/issues/issue-29710.rs
+++ b/tests/ui/lint/unused-results-lint-triggered-by-derive-debug-29710.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/29710
 //@ check-pass
 #![deny(unused_results)]
 #![allow(dead_code)]
diff --git a/tests/ui/issues/issue-9047.rs b/tests/ui/loops/loop-with-label-9047.rs
index 97733588d51..29e6dba0b9e 100644
--- a/tests/ui/issues/issue-9047.rs
+++ b/tests/ui/loops/loop-with-label-9047.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9047
 //@ run-pass
 #![allow(unused_mut)]
 #![allow(unused_variables)]
diff --git a/tests/ui/macros/issue-111749.stderr b/tests/ui/macros/issue-111749.stderr
index 7db2b8e6ad1..884537ef531 100644
--- a/tests/ui/macros/issue-111749.stderr
+++ b/tests/ui/macros/issue-111749.stderr
@@ -16,3 +16,14 @@ LL |     cbor_map! { #[test(test)] 4};
 
 error: aborting due to 2 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: attribute must be of the form `#[test]`
+  --> $DIR/issue-111749.rs:8:17
+   |
+LL |     cbor_map! { #[test(test)] 4};
+   |                 ^^^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
diff --git a/tests/ui/issues/issue-9110.rs b/tests/ui/macros/macro-expansion-module-structure-9110.rs
index 47533dc43b5..b6241a7c18e 100644
--- a/tests/ui/issues/issue-9110.rs
+++ b/tests/ui/macros/macro-expansion-module-structure-9110.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9110
 //@ check-pass
 #![allow(dead_code)]
 #![allow(non_snake_case)]
diff --git a/tests/ui/issues/issue-9737.rs b/tests/ui/macros/macro-invocation-with-variable-in-scope-9737.rs
index a8a17e58dd6..957c2e3f103 100644
--- a/tests/ui/issues/issue-9737.rs
+++ b/tests/ui/macros/macro-invocation-with-variable-in-scope-9737.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9737
 //@ run-pass
 #![allow(unused_variables)]
 macro_rules! f {
diff --git a/tests/ui/issues/issue-25386.rs b/tests/ui/macros/private-struct-member-macro-access-25386.rs
index b26cc77680d..88e5a22a699 100644
--- a/tests/ui/issues/issue-25386.rs
+++ b/tests/ui/macros/private-struct-member-macro-access-25386.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/25386
 mod stuff {
     pub struct Item {
         c_object: Box<CObj>,
diff --git a/tests/ui/issues/issue-25386.stderr b/tests/ui/macros/private-struct-member-macro-access-25386.stderr
index 720b77866a5..d02a41848f4 100644
--- a/tests/ui/issues/issue-25386.stderr
+++ b/tests/ui/macros/private-struct-member-macro-access-25386.stderr
@@ -1,5 +1,5 @@
 error[E0616]: field `c_object` of struct `Item` is private
-  --> $DIR/issue-25386.rs:19:16
+  --> $DIR/private-struct-member-macro-access-25386.rs:20:16
    |
 LL |         (*$var.c_object).$member.is_some()
    |                ^^^^^^^^ private field
diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr
index 8c22919a1c2..60ea5da761d 100644
--- a/tests/ui/malformed/malformed-regressions.stderr
+++ b/tests/ui/malformed/malformed-regressions.stderr
@@ -46,3 +46,58 @@ LL | #[inline = ""]
 
 error: aborting due to 5 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+  --> $DIR/malformed-regressions.rs:1:1
+   |
+LL | #[doc]
+   | ^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+  --> $DIR/malformed-regressions.rs:7:1
+   |
+LL | #[link]
+   | ^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+  --> $DIR/malformed-regressions.rs:9:1
+   |
+LL | #[link = ""]
+   | ^^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
+  --> $DIR/malformed-regressions.rs:3:1
+   |
+LL | #[ignore()]
+   | ^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
+Future breakage diagnostic:
+error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+  --> $DIR/malformed-regressions.rs:5:1
+   |
+LL | #[inline = ""]
+   | ^^^^^^^^^^^^^^
+   |
+   = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
diff --git a/tests/ui/issues/issue-92741.fixed b/tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.fixed
index cb37d25273f..c165779e402 100644
--- a/tests/ui/issues/issue-92741.fixed
+++ b/tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.fixed
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/92741
 //@ run-rustfix
 fn main() {}
 fn _foo() -> bool {
diff --git a/tests/ui/issues/issue-92741.rs b/tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.rs
index 1c5d5810a57..b3fa5f77308 100644
--- a/tests/ui/issues/issue-92741.rs
+++ b/tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/92741
 //@ run-rustfix
 fn main() {}
 fn _foo() -> bool {
diff --git a/tests/ui/issues/issue-92741.stderr b/tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.stderr
index 49315e7a8bf..60917d9a63e 100644
--- a/tests/ui/issues/issue-92741.stderr
+++ b/tests/ui/mismatched_types/newlines-in-diagnostic-fix-suggestions-92741.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-92741.rs:4:5
+  --> $DIR/newlines-in-diagnostic-fix-suggestions-92741.rs:5:5
    |
 LL |   fn _foo() -> bool {
    |                ---- expected `bool` because of return type
@@ -15,7 +15,7 @@ LL -     mut
    |
 
 error[E0308]: mismatched types
-  --> $DIR/issue-92741.rs:10:5
+  --> $DIR/newlines-in-diagnostic-fix-suggestions-92741.rs:11:5
    |
 LL |   fn _bar() -> bool {
    |                ---- expected `bool` because of return type
@@ -31,7 +31,7 @@ LL +     if true { true } else { false }
    |
 
 error[E0308]: mismatched types
-  --> $DIR/issue-92741.rs:15:5
+  --> $DIR/newlines-in-diagnostic-fix-suggestions-92741.rs:16:5
    |
 LL |   fn _baz() -> bool {
    |                ---- expected `bool` because of return type
diff --git a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
index 51d0f85c031..dfc983bf487 100644
--- a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
+++ b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
@@ -10,6 +10,11 @@ LL |     let _f = to_fn(|| test(i));
    |                    |
    |                    captured by this `Fn` closure
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:3:33
+   |
+LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+   |                                 ^^^^^
 help: consider cloning the value if the performance cost is acceptable
    |
 LL |     let _f = to_fn(|| test(i.clone()));
diff --git a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
index 57546037006..7f9a8e50dae 100644
--- a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
+++ b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr
@@ -10,6 +10,11 @@ LL |        expect_fn(|| drop(x.0));
    |                  |
    |                  captured by this `Fn` closure
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/issue-52663-span-decl-captured-variable.rs:1:33
+   |
+LL | fn expect_fn<F>(f: F) where F : Fn() {
+   |                                 ^^^^
 help: consider cloning the value if the performance cost is acceptable
    |
 LL |        expect_fn(|| drop(x.0.clone()));
diff --git a/tests/ui/issues/issue-99838.rs b/tests/ui/packed/misaligned-reference-drop-field-99838.rs
index 687b47fbe71..58e168162cb 100644
--- a/tests/ui/issues/issue-99838.rs
+++ b/tests/ui/packed/misaligned-reference-drop-field-99838.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/99838
 //@ run-pass
 
 use std::hint;
diff --git a/tests/ui/issues/issue-pr29383.rs b/tests/ui/pattern/unit-variant-pattern-matching-29383.rs
index 2bcc0aa2782..e339dc01f46 100644
--- a/tests/ui/issues/issue-pr29383.rs
+++ b/tests/ui/pattern/unit-variant-pattern-matching-29383.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/29383
 enum E {
     A,
     B,
diff --git a/tests/ui/issues/issue-pr29383.stderr b/tests/ui/pattern/unit-variant-pattern-matching-29383.stderr
index 57783d75ba1..e30837568a5 100644
--- a/tests/ui/issues/issue-pr29383.stderr
+++ b/tests/ui/pattern/unit-variant-pattern-matching-29383.stderr
@@ -1,5 +1,5 @@
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::A`
-  --> $DIR/issue-pr29383.rs:9:14
+  --> $DIR/unit-variant-pattern-matching-29383.rs:10:14
    |
 LL |     A,
    |     - `E::A` defined here
@@ -8,7 +8,7 @@ LL |         Some(E::A(..)) => {}
    |              ^^^^^^^^ help: use this syntax instead: `E::A`
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::B`
-  --> $DIR/issue-pr29383.rs:11:14
+  --> $DIR/unit-variant-pattern-matching-29383.rs:12:14
    |
 LL |     B,
    |     - `E::B` defined here
diff --git a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
index f37dc320fa3..8081f7b3a8b 100644
--- a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
+++ b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr
@@ -44,6 +44,7 @@ LL |
 LL |         foo(f);
    |             ^ move occurs because `f` has type `{closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 52:58}`, which does not implement the `Copy` trait
    |
+   = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
 help: consider cloning the value if the performance cost is acceptable
    |
 LL |         foo(f.clone());
diff --git a/tests/ui/issues/issue-9249.rs b/tests/ui/static/static-string-slice-9249.rs
index b98ba050521..da099117bd4 100644
--- a/tests/ui/issues/issue-9249.rs
+++ b/tests/ui/static/static-string-slice-9249.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/9249
 //@ check-pass
 #![allow(dead_code)]
 
diff --git a/tests/ui/issues/issue-24365.rs b/tests/ui/structs/struct-field-access-errors-24365.rs
index da195116047..13a95cd1cca 100644
--- a/tests/ui/issues/issue-24365.rs
+++ b/tests/ui/structs/struct-field-access-errors-24365.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/24365
 pub enum Attribute {
     Code {attr_name_idx: u16},
 }
diff --git a/tests/ui/issues/issue-24365.stderr b/tests/ui/structs/struct-field-access-errors-24365.stderr
index 3f6ed0231d8..65275af4701 100644
--- a/tests/ui/issues/issue-24365.stderr
+++ b/tests/ui/structs/struct-field-access-errors-24365.stderr
@@ -1,17 +1,17 @@
 error[E0609]: no field `b` on type `Foo`
-  --> $DIR/issue-24365.rs:10:22
+  --> $DIR/struct-field-access-errors-24365.rs:11:22
    |
 LL |     println!("{}", a.b);
    |                      ^ unknown field
 
 error[E0609]: no field `attr_name_idx` on type `&Attribute`
-  --> $DIR/issue-24365.rs:17:18
+  --> $DIR/struct-field-access-errors-24365.rs:18:18
    |
 LL |     let z = (&x).attr_name_idx;
    |                  ^^^^^^^^^^^^^ unknown field
 
 error[E0609]: no field `attr_name_idx` on type `Attribute`
-  --> $DIR/issue-24365.rs:18:15
+  --> $DIR/struct-field-access-errors-24365.rs:19:15
    |
 LL |     let y = x.attr_name_idx;
    |               ^^^^^^^^^^^^^ unknown field
diff --git a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs
index 44eac3691a3..34088f219b2 100644
--- a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs
+++ b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.rs
@@ -11,8 +11,55 @@ struct X(Y);
 struct Y;
 
 fn consume_fn<F: Fn()>(_f: F) { }
+//~^ HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
 
 fn consume_fnmut<F: FnMut()>(_f: F) { }
+//~^ HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+//~| HELP `Fn` and `FnMut` closures
+
+trait T {
+    fn consume_fn<F: Fn()>(_f: F) { }
+    //~^ HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+    //~^ HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+    //~| HELP `Fn` and `FnMut` closures
+}
+impl T for () {}
 
 pub fn main() { }
 
@@ -73,6 +120,120 @@ fn move_into_fn() {
     });
 }
 
+fn move_into_assoc_fn() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let x = X(Y);
+
+    // move into Fn
+
+    <() as T>::consume_fn(|| {
+        let X(_t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        if let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        while let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(_t)
+            | Either::Two(_t) => (),
+        }
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(_t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+
+        let X(mut _t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        if let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        while let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(mut _t)
+            | Either::Two(mut _t) => (),
+        }
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(mut _t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+    });
+}
+
+fn move_into_method() {
+    let e = Either::One(X(Y));
+    let mut em = Either::One(X(Y));
+
+    let x = X(Y);
+
+    // move into Fn
+
+    ().method_consume_fn(|| {
+        let X(_t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        if let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        while let Either::One(_t) = e { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(_t)
+            | Either::Two(_t) => (),
+        }
+        match e {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(_t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+
+        let X(mut _t) = x;
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        if let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        while let Either::One(mut _t) = em { }
+        //~^ ERROR cannot move
+        //~| HELP consider borrowing here
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(mut _t)
+            | Either::Two(mut _t) => (),
+        }
+        match em {
+            //~^ ERROR cannot move
+            //~| HELP consider borrowing here
+            Either::One(mut _t) => (),
+            Either::Two(ref _t) => (),
+            // FIXME: should suggest removing `ref` too
+        }
+    });
+}
+
 fn move_into_fnmut() {
     let e = Either::One(X(Y));
     let mut em = Either::One(X(Y));
diff --git a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
index edda2cbc735..132a31c8f7c 100644
--- a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
+++ b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:28:21
+  --> $DIR/move-into-closure.rs:75:21
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -12,13 +12,18 @@ LL |         let X(_t) = x;
    |               data moved here
    |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         let X(_t) = &x;
    |                     +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:31:34
+  --> $DIR/move-into-closure.rs:78:34
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -32,13 +37,18 @@ LL |         if let Either::One(_t) = e { }
    |                            data moved here
    |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         if let Either::One(_t) = &e { }
    |                                  +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:34:37
+  --> $DIR/move-into-closure.rs:81:37
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -52,13 +62,18 @@ LL |         while let Either::One(_t) = e { }
    |                               data moved here
    |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         while let Either::One(_t) = &e { }
    |                                     +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:37:15
+  --> $DIR/move-into-closure.rs:84:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -75,13 +90,18 @@ LL |             Either::One(_t)
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         match &e {
    |               +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:43:15
+  --> $DIR/move-into-closure.rs:90:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -98,13 +118,18 @@ LL |             Either::One(_t) => (),
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         match &e {
    |               +
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:51:25
+  --> $DIR/move-into-closure.rs:98:25
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -118,13 +143,18 @@ LL |         let X(mut _t) = x;
    |               data moved here
    |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         let X(mut _t) = &x;
    |                         +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:54:38
+  --> $DIR/move-into-closure.rs:101:38
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -138,13 +168,18 @@ LL |         if let Either::One(mut _t) = em { }
    |                            data moved here
    |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         if let Either::One(mut _t) = &em { }
    |                                      +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:57:41
+  --> $DIR/move-into-closure.rs:104:41
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -158,13 +193,18 @@ LL |         while let Either::One(mut _t) = em { }
    |                               data moved here
    |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         while let Either::One(mut _t) = &em { }
    |                                         +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:60:15
+  --> $DIR/move-into-closure.rs:107:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -181,13 +221,18 @@ LL |             Either::One(mut _t)
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
 help: consider borrowing here
    |
 LL |         match &em {
    |               +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:66:15
+  --> $DIR/move-into-closure.rs:113:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -204,13 +249,540 @@ LL |             Either::One(mut _t) => (),
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:13:18
+   |
+LL | fn consume_fn<F: Fn()>(_f: F) { }
+   |                  ^^^^
+help: consider borrowing here
+   |
+LL |         match &em {
+   |               +
+
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:132:21
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+LL |         let X(_t) = x;
+   |               --    ^
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         let X(_t) = &x;
+   |                     +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:135:34
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         if let Either::One(_t) = e { }
+   |                            --    ^
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         if let Either::One(_t) = &e { }
+   |                                  +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:138:37
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         while let Either::One(_t) = e { }
+   |                               --    ^
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         while let Either::One(_t) = &e { }
+   |                                     +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:141:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^
+...
+LL |             Either::One(_t)
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         match &e {
+   |               +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:147:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^
+...
+LL |             Either::One(_t) => (),
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         match &e {
+   |               +
+
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:155:25
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         let X(mut _t) = x;
+   |               ------    ^
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         let X(mut _t) = &x;
+   |                         +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:158:38
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         if let Either::One(mut _t) = em { }
+   |                            ------    ^^
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         if let Either::One(mut _t) = &em { }
+   |                                      +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:161:41
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         while let Either::One(mut _t) = em { }
+   |                               ------    ^^
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         while let Either::One(mut _t) = &em { }
+   |                                         +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:164:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^
+...
+LL |             Either::One(mut _t)
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         match &em {
+   |               +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:170:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     <() as T>::consume_fn(|| {
+   |                           -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:39:22
+   |
+LL |     fn consume_fn<F: Fn()>(_f: F) { }
+   |                      ^^^^
+help: consider borrowing here
+   |
+LL |         match &em {
+   |               +
+
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:189:21
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+LL |         let X(_t) = x;
+   |               --    ^
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         let X(_t) = &x;
+   |                     +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:192:34
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         if let Either::One(_t) = e { }
+   |                            --    ^
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         if let Either::One(_t) = &e { }
+   |                                  +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:195:37
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         while let Either::One(_t) = e { }
+   |                               --    ^
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         while let Either::One(_t) = &e { }
+   |                                     +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:198:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^
+...
+LL |             Either::One(_t)
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         match &e {
+   |               +
+
+error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:204:15
+   |
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^
+...
+LL |             Either::One(_t) => (),
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         match &e {
+   |               +
+
+error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:212:25
+   |
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         let X(mut _t) = x;
+   |               ------    ^
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         let X(mut _t) = &x;
+   |                         +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:215:38
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         if let Either::One(mut _t) = em { }
+   |                            ------    ^^
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         if let Either::One(mut _t) = &em { }
+   |                                      +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:218:41
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         while let Either::One(mut _t) = em { }
+   |                               ------    ^^
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         while let Either::One(mut _t) = &em { }
+   |                                         +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:221:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^
+...
+LL |             Either::One(mut _t)
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
+help: consider borrowing here
+   |
+LL |         match &em {
+   |               +
+
+error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
+  --> $DIR/move-into-closure.rs:227:15
+   |
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     ().method_consume_fn(|| {
+   |                          -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:50:29
+   |
+LL |     fn method_consume_fn<F: Fn()>(&self, _f: F) { }
+   |                             ^^^^
 help: consider borrowing here
    |
 LL |         match &em {
    |               +
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:85:21
+  --> $DIR/move-into-closure.rs:246:21
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -223,13 +795,18 @@ LL |         let X(_t) = x;
    |               data moved here
    |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         let X(_t) = &x;
    |                     +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:88:34
+  --> $DIR/move-into-closure.rs:249:34
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -243,13 +820,18 @@ LL |         if let Either::One(_t) = e { }
    |                            data moved here
    |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         if let Either::One(_t) = &e { }
    |                                  +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:91:37
+  --> $DIR/move-into-closure.rs:252:37
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -263,13 +845,18 @@ LL |         while let Either::One(_t) = e { }
    |                               data moved here
    |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         while let Either::One(_t) = &e { }
    |                                     +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:94:15
+  --> $DIR/move-into-closure.rs:255:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -286,13 +873,18 @@ LL |             Either::One(_t)
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         match &e {
    |               +
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:100:15
+  --> $DIR/move-into-closure.rs:261:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -309,13 +901,18 @@ LL |             Either::One(_t) => (),
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         match &e {
    |               +
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:108:25
+  --> $DIR/move-into-closure.rs:269:25
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -329,13 +926,18 @@ LL |         let X(mut _t) = x;
    |               data moved here
    |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         let X(mut _t) = &x;
    |                         +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:111:38
+  --> $DIR/move-into-closure.rs:272:38
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -349,13 +951,18 @@ LL |         if let Either::One(mut _t) = em { }
    |                            data moved here
    |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         if let Either::One(mut _t) = &em { }
    |                                      +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:114:41
+  --> $DIR/move-into-closure.rs:275:41
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -369,13 +976,18 @@ LL |         while let Either::One(mut _t) = em { }
    |                               data moved here
    |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         while let Either::One(mut _t) = &em { }
    |                                         +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:117:15
+  --> $DIR/move-into-closure.rs:278:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -392,13 +1004,18 @@ LL |             Either::One(mut _t)
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         match &em {
    |               +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:123:15
+  --> $DIR/move-into-closure.rs:284:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -415,13 +1032,18 @@ LL |             Either::One(mut _t) => (),
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         match &em {
    |               +
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:130:15
+  --> $DIR/move-into-closure.rs:291:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -438,11 +1060,16 @@ LL |             Either::One(mut _t) => (),
    |                         data moved here
    |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/move-into-closure.rs:25:21
+   |
+LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
+   |                     ^^^^^^^
 help: consider borrowing here
    |
 LL |         match &em {
    |               +
 
-error: aborting due to 21 previous errors
+error: aborting due to 41 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/suggestions/option-content-move2.stderr b/tests/ui/suggestions/option-content-move2.stderr
index c73e874b403..c8aa6667b58 100644
--- a/tests/ui/suggestions/option-content-move2.stderr
+++ b/tests/ui/suggestions/option-content-move2.stderr
@@ -14,6 +14,11 @@ LL |
 LL |             var = Some(NotCopyable);
    |             --- variable moved due to use in closure
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/option-content-move2.rs:5:12
+   |
+LL | fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+   |            ^^^^^^^^^^^^
 note: if `NotCopyable` implemented `Clone`, you could clone the value
   --> $DIR/option-content-move2.rs:1:1
    |
@@ -38,6 +43,12 @@ LL |         move || {
 LL |
 LL |             var = Some(NotCopyableButCloneable);
    |             --- variable moved due to use in closure
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/option-content-move2.rs:5:12
+   |
+LL | fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+   |            ^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/option-content-move3.stderr b/tests/ui/suggestions/option-content-move3.stderr
index 68c52352a65..2c9a86c036b 100644
--- a/tests/ui/suggestions/option-content-move3.stderr
+++ b/tests/ui/suggestions/option-content-move3.stderr
@@ -9,6 +9,7 @@ LL |         move || {
 LL |             let x = var;
    |                     ^^^ move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
    |
+   = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
 note: if `NotCopyable` implemented `Clone`, you could clone the value
   --> $DIR/option-content-move3.rs:2:1
    |
@@ -37,6 +38,11 @@ LL |         move || {
 LL |             let x = var;
    |                     --- variable moved due to use in closure
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/option-content-move3.rs:6:12
+   |
+LL | fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+   |            ^^^^^^^^^^^^
 note: if `NotCopyable` implemented `Clone`, you could clone the value
   --> $DIR/option-content-move3.rs:2:1
    |
@@ -57,6 +63,7 @@ LL |         move || {
 LL |             let x = var;
    |                     ^^^ move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait
    |
+   = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
 help: consider borrowing here
    |
 LL |             let x = &var;
@@ -77,6 +84,11 @@ LL |         move || {
 LL |             let x = var;
    |                     --- variable moved due to use in closure
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/option-content-move3.rs:6:12
+   |
+LL | fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+   |            ^^^^^^^^^^^^
 help: consider cloning the value before moving it into the closure
    |
 LL ~         {
diff --git a/tests/ui/issues/issue-30756.rs b/tests/ui/thread-local/thread-local-with-attributes-30756.rs
index d103776406c..fcf7bb813c8 100644
--- a/tests/ui/issues/issue-30756.rs
+++ b/tests/ui/thread-local/thread-local-with-attributes-30756.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/30756
 //@ run-pass
 #![forbid(unsafe_code)]
 
diff --git a/tests/ui/issues/issue-30236.rs b/tests/ui/typeck/unused-type-parameter-span-30236.rs
index 08d08a54402..bcdc922a71b 100644
--- a/tests/ui/issues/issue-30236.rs
+++ b/tests/ui/typeck/unused-type-parameter-span-30236.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/30236
 type Foo<
     Unused //~ ERROR type parameter `Unused` is never used
     > = u8;
diff --git a/tests/ui/issues/issue-30236.stderr b/tests/ui/typeck/unused-type-parameter-span-30236.stderr
index bfe374a653f..038bd1ebd28 100644
--- a/tests/ui/issues/issue-30236.stderr
+++ b/tests/ui/typeck/unused-type-parameter-span-30236.stderr
@@ -1,5 +1,5 @@
 error[E0091]: type parameter `Unused` is never used
-  --> $DIR/issue-30236.rs:2:5
+  --> $DIR/unused-type-parameter-span-30236.rs:3:5
    |
 LL |     Unused
    |     ^^^^^^ unused type parameter
diff --git a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
index 8d9a61cb681..9d87402a15b 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
@@ -10,6 +10,11 @@ LL |         let f = to_fn(|| drop(x));
    |                       |
    |                       captured by this `Fn` closure
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/unboxed-closure-illegal-move.rs:7:33
+   |
+LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+   |                                 ^^^^^
 help: consider cloning the value if the performance cost is acceptable
    |
 LL |         let f = to_fn(|| drop(x.clone()));
@@ -27,6 +32,11 @@ LL |         let f = to_fn_mut(|| drop(x));
    |                           |
    |                           captured by this `FnMut` closure
    |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/unboxed-closure-illegal-move.rs:8:37
+   |
+LL | fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
+   |                                     ^^^^^^^^
 help: consider cloning the value if the performance cost is acceptable
    |
 LL |         let f = to_fn_mut(|| drop(x.clone()));
@@ -43,6 +53,12 @@ LL |         let f = to_fn(move || drop(x));
    |                       -------      ^ `x` is moved here
    |                       |
    |                       captured by this `Fn` closure
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/unboxed-closure-illegal-move.rs:7:33
+   |
+LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+   |                                 ^^^^^
 
 error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
   --> $DIR/unboxed-closure-illegal-move.rs:32:40
@@ -55,6 +71,12 @@ LL |         let f = to_fn_mut(move || drop(x));
    |                           -------      ^ `x` is moved here
    |                           |
    |                           captured by this `FnMut` closure
+   |
+help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
+  --> $DIR/unboxed-closure-illegal-move.rs:8:37
+   |
+LL | fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
+   |                                     ^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/issues/issue-88150.rs b/tests/ui/uninhabited/uninhabited-type-layout-computation-88150.rs
index 1dadba307c0..1387c5b6c10 100644
--- a/tests/ui/issues/issue-88150.rs
+++ b/tests/ui/uninhabited/uninhabited-type-layout-computation-88150.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/88150
 //@ run-pass
 //@ compile-flags:-C debuginfo=2
 //@ edition:2018