about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-21 17:02:31 +0000
committerbors <bors@rust-lang.org>2022-07-21 17:02:31 +0000
commitaf7ab3447079fddc51c6c7749b160d24769f7c16 (patch)
treec3313ceb71c87ffe157e6d68e967877761f7d836
parent1673f1450eeaf4a5452e086db0fe2ae274a0144f (diff)
parentaf64d93dbb8239dd8aa6e0fcaa89490467f1344f (diff)
downloadrust-af7ab3447079fddc51c6c7749b160d24769f7c16.tar.gz
rust-af7ab3447079fddc51c6c7749b160d24769f7c16.zip
Auto merge of #99567 - matthiaskrgr:rollup-08hh3r4, r=matthiaskrgr
Rollup of 11 pull requests

Successful merges:

 - #98707 (std: use futex-based locks on Fuchsia)
 - #99413 (Add `PhantomData` marker for dropck to `BTreeMap`)
 - #99454 (Add map_continue and continue_value combinators to ControlFlow)
 - #99523 (Fix the stable version of `AsFd for Arc<T>` and `Box<T>`)
 - #99526 (Normalize the arg spans to be within the call span)
 - #99528 (couple of clippy::perf fixes)
 - #99549 (Add regression test for #52304)
 - #99552 (Rewrite `orphan_check_trait_ref` to use a `TypeVisitor`)
 - #99557 (Edit `rustc_index::vec::IndexVec::pick3_mut` docs)
 - #99558 (Fix `remap_constness`)
 - #99559 (Remove unused field in ItemKind::KeywordItem)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_error_messages/src/lib.rs2
-rw-r--r--compiler/rustc_index/src/vec.rs8
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs2
-rw-r--r--compiler/rustc_macros/src/diagnostics/fluent.rs6
-rw-r--r--compiler/rustc_middle/src/ty/consts/valtree.rs10
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs13
-rw-r--r--compiler/rustc_privacy/src/lib.rs1
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs2
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs319
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs6
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs26
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs5
-rw-r--r--library/alloc/src/collections/btree/map.rs30
-rw-r--r--library/core/src/ops/control_flow.rs35
-rw-r--r--library/std/src/os/fd/owned.rs4
-rw-r--r--library/std/src/sys/unix/futex.rs28
-rw-r--r--library/std/src/sys/unix/locks/fuchsia_mutex.rs165
-rw-r--r--library/std/src/sys/unix/locks/futex_condvar.rs58
-rw-r--r--library/std/src/sys/unix/locks/futex_mutex.rs (renamed from library/std/src/sys/unix/locks/futex.rs)56
-rw-r--r--library/std/src/sys/unix/locks/mod.rs13
-rw-r--r--src/librustdoc/clean/types.rs7
-rw-r--r--src/librustdoc/clean/utils.rs2
-rw-r--r--src/librustdoc/fold.rs2
-rw-r--r--src/librustdoc/formats/cache.rs2
-rw-r--r--src/librustdoc/formats/item_type.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs4
-rw-r--r--src/librustdoc/json/conversions.rs4
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs2
-rw-r--r--src/librustdoc/passes/stripper.rs2
-rw-r--r--src/librustdoc/visit.rs2
-rw-r--r--src/test/ui/btreemap/btreemap_dropck.rs16
-rw-r--r--src/test/ui/btreemap/btreemap_dropck.stderr13
-rw-r--r--src/test/ui/generator/issue-52304.rs11
-rw-r--r--src/test/ui/impl-trait/negative-reasoning.stderr2
-rw-r--r--src/test/ui/inference/deref-suggestion.rs3
-rw-r--r--src/test/ui/inference/deref-suggestion.stderr24
-rw-r--r--src/test/ui/issues/issue-72554.rs5
-rw-r--r--src/test/ui/issues/issue-72554.stderr19
41 files changed, 577 insertions, 344 deletions
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 6b961eaeb42..2ac5c1960cd 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -299,7 +299,7 @@ impl DiagnosticMessage {
     /// - If `self` is non-translatable then return `self`'s message.
     pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
         let attr = match sub {
-            SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s.clone()),
+            SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
             SubdiagnosticMessage::FluentIdentifier(id) => {
                 return DiagnosticMessage::FluentIdentifier(id, None);
             }
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 1a55519d7b1..30ff364210d 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -234,7 +234,9 @@ impl<I: Idx, T> IndexVec<I, T> {
         self.raw.get_mut(index.index())
     }
 
-    /// Returns mutable references to two distinct elements, a and b. Panics if a == b.
+    /// Returns mutable references to two distinct elements, `a` and `b`.
+    ///
+    /// Panics if `a == b`.
     #[inline]
     pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) {
         let (ai, bi) = (a.index(), b.index());
@@ -249,7 +251,9 @@ impl<I: Idx, T> IndexVec<I, T> {
         }
     }
 
-    /// Returns mutable references to three distinct elements or panics otherwise.
+    /// Returns mutable references to three distinct elements.
+    ///
+    /// Panics if the elements are not distinct.
     #[inline]
     pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) {
         let (ai, bi, ci) = (a.index(), b.index(), c.index());
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 5c5275b7cfb..6c9561925fe 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -212,7 +212,7 @@ impl DiagnosticDeriveBuilder {
                 }
                 NestedMeta::Meta(meta @ Meta::NameValue(_))
                     if !is_help_note_or_warn
-                        && meta.path().segments.last().unwrap().ident.to_string() == "code" =>
+                        && meta.path().segments.last().unwrap().ident == "code" =>
                 {
                     // don't error for valid follow-up attributes
                 }
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index 1170d2b3c59..562d5e9f4d2 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -194,8 +194,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                 let snake_name = Ident::new(
                     // FIXME: should probably trim prefix, not replace all occurrences
                     &name
-                        .replace(&format!("{}-", res.ident).replace("_", "-"), "")
-                        .replace("-", "_"),
+                        .replace(&format!("{}-", res.ident).replace('_', "-"), "")
+                        .replace('-', "_"),
                     span,
                 );
                 constants.extend(quote! {
@@ -207,7 +207,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                 });
 
                 for Attribute { id: Identifier { name: attr_name }, .. } in attributes {
-                    let snake_name = Ident::new(&attr_name.replace("-", "_"), span);
+                    let snake_name = Ident::new(&attr_name.replace('-', "_"), span);
                     if !previous_attrs.insert(snake_name.clone()) {
                         continue;
                     }
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index 973dc3dd4a1..c7653bdbe84 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -88,19 +88,17 @@ impl<'tcx> ValTree<'tcx> {
                     let leafs = self
                         .unwrap_branch()
                         .into_iter()
-                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap())
-                        .collect::<Vec<_>>();
+                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap());
 
-                    return Some(tcx.arena.alloc_from_iter(leafs.into_iter()));
+                    return Some(tcx.arena.alloc_from_iter(leafs));
                 }
                 ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {
                     let leafs = self
                         .unwrap_branch()
                         .into_iter()
-                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap())
-                        .collect::<Vec<_>>();
+                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap());
 
-                    return Some(tcx.arena.alloc_from_iter(leafs.into_iter()));
+                    return Some(tcx.arena.alloc_from_iter(leafs));
                 }
                 _ => {}
             },
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 53919826bf6..4f39ec31a83 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -790,22 +790,15 @@ pub struct TraitPredicate<'tcx> {
 pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
 
 impl<'tcx> TraitPredicate<'tcx> {
-    pub fn remap_constness(&mut self, tcx: TyCtxt<'tcx>, param_env: &mut ParamEnv<'tcx>) {
-        if std::intrinsics::unlikely(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) {
-            // remap without changing constness of this predicate.
-            // this is because `T: ~const Drop` has a different meaning to `T: Drop`
-            // FIXME(fee1-dead): remove this logic after beta bump
-            param_env.remap_constness_with(self.constness)
-        } else {
-            *param_env = param_env.with_constness(self.constness.and(param_env.constness()))
-        }
+    pub fn remap_constness(&mut self, param_env: &mut ParamEnv<'tcx>) {
+        *param_env = param_env.with_constness(self.constness.and(param_env.constness()))
     }
 
     /// Remap the constness of this predicate before emitting it for diagnostics.
     pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
         // this is different to `remap_constness` that callees want to print this predicate
         // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the
-        // param_env is not const because we it is always satisfied in non-const contexts.
+        // param_env is not const because it is always satisfied in non-const contexts.
         if let hir::Constness::NotConst = param_env.constness() {
             self.constness = ty::BoundConstness::NotConst;
         }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9a835808d49..390d6f5a856 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1754,7 +1754,6 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                 || self.in_assoc_ty
                 || self.tcx.resolutions(()).has_pub_restricted
             {
-                let descr = descr.to_string();
                 let vis_span =
                     self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
                 if kind == "trait" {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index df13136dcce..d74e26fc844 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2608,7 +2608,7 @@ fn show_candidates(
                 "item"
             };
             let plural_descr =
-                if descr.ends_with("s") { format!("{}es", descr) } else { format!("{}s", descr) };
+                if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) };
 
             let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr);
             let mut has_colon = false;
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f99b20efd71..21b1b0b4ebf 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -535,7 +535,7 @@ mod parse {
     ) -> bool {
         match v {
             Some(s) => {
-                for s in s.split(",") {
+                for s in s.split(',') {
                     let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false };
                     slot.push((pass_name.to_string(), &s[..1] == "+"));
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 52ca23c4b30..9983438233e 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -22,11 +22,12 @@ use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use std::fmt::Debug;
 use std::iter;
+use std::ops::ControlFlow;
 
 /// Whether we do the orphan check relative to this crate or
 /// to some remote crate.
@@ -578,220 +579,146 @@ fn orphan_check_trait_ref<'tcx>(
         );
     }
 
-    // Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only
-    // if at least one of the following is true:
-    //
-    // - Trait is a local trait
-    // (already checked in orphan_check prior to calling this function)
-    // - All of
-    //     - At least one of the types T0..=Tn must be a local type.
-    //      Let Ti be the first such type.
-    //     - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti)
-    //
-    fn uncover_fundamental_ty<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        ty: Ty<'tcx>,
-        in_crate: InCrate,
-    ) -> Vec<Ty<'tcx>> {
-        // FIXME: this is currently somewhat overly complicated,
-        // but fixing this requires a more complicated refactor.
-        if !contained_non_local_types(tcx, ty, in_crate).is_empty() {
-            if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
-                return inner_tys
-                    .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                    .collect();
+    let mut checker = OrphanChecker::new(tcx, in_crate);
+    match trait_ref.visit_with(&mut checker) {
+        ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
+        ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => {
+            // Does there exist some local type after the `ParamTy`.
+            checker.search_first_local_ty = true;
+            if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) =
+                trait_ref.visit_with(&mut checker).break_value()
+            {
+                Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty)))
+            } else {
+                Err(OrphanCheckErr::UncoveredTy(ty, None))
             }
         }
-
-        vec![ty]
-    }
-
-    let mut non_local_spans = vec![];
-    for (i, input_ty) in trait_ref
-        .substs
-        .types()
-        .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-        .enumerate()
-    {
-        debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
-        let non_local_tys = contained_non_local_types(tcx, input_ty, in_crate);
-        if non_local_tys.is_empty() {
-            debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
-            return Ok(());
-        } else if let ty::Param(_) = input_ty.kind() {
-            debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty);
-            let local_type = trait_ref
-                .substs
-                .types()
-                .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                .find(|&ty| ty_is_local_constructor(tcx, ty, in_crate));
-
-            debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
-
-            return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type));
-        }
-
-        non_local_spans.extend(non_local_tys.into_iter().map(|input_ty| (input_ty, i == 0)));
+        ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()),
     }
-    // If we exit above loop, never found a local type.
-    debug!("orphan_check_trait_ref: no local type");
-    Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
 }
 
-/// Returns a list of relevant non-local types for `ty`.
-///
-/// This is just `ty` itself unless `ty` is `#[fundamental]`,
-/// in which case we recursively look into this type.
-///
-/// If `ty` is local itself, this method returns an empty `Vec`.
-///
-/// # Examples
-///
-/// - `u32` is not local, so this returns `[u32]`.
-/// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`.
-/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`.
-/// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local.
-fn contained_non_local_types<'tcx>(
+struct OrphanChecker<'tcx> {
     tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
     in_crate: InCrate,
-) -> Vec<Ty<'tcx>> {
-    if ty_is_local_constructor(tcx, ty, in_crate) {
-        Vec::new()
-    } else {
-        match fundamental_ty_inner_tys(tcx, ty) {
-            Some(inner_tys) => {
-                inner_tys.flat_map(|ty| contained_non_local_types(tcx, ty, in_crate)).collect()
-            }
-            None => vec![ty],
+    in_self_ty: bool,
+    /// Ignore orphan check failures and exclusively search for the first
+    /// local type.
+    search_first_local_ty: bool,
+    non_local_tys: Vec<(Ty<'tcx>, bool)>,
+}
+
+impl<'tcx> OrphanChecker<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self {
+        OrphanChecker {
+            tcx,
+            in_crate,
+            in_self_ty: true,
+            search_first_local_ty: false,
+            non_local_tys: Vec::new(),
         }
     }
-}
 
-/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the
-/// type parameters of the ADT, or `T`, respectively. For non-fundamental
-/// types, returns `None`.
-fn fundamental_ty_inner_tys<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Option<impl Iterator<Item = Ty<'tcx>>> {
-    let (first_ty, rest_tys) = match *ty.kind() {
-        ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()),
-        ty::Adt(def, substs) if def.is_fundamental() => {
-            let mut types = substs.types();
-
-            // FIXME(eddyb) actually validate `#[fundamental]` up-front.
-            match types.next() {
-                None => {
-                    tcx.sess.span_err(
-                        tcx.def_span(def.did()),
-                        "`#[fundamental]` requires at least one type parameter",
-                    );
-
-                    return None;
-                }
+    fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
+        self.non_local_tys.push((t, self.in_self_ty));
+        ControlFlow::CONTINUE
+    }
 
-                Some(first_ty) => (first_ty, types),
-            }
+    fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
+        if self.search_first_local_ty {
+            ControlFlow::CONTINUE
+        } else {
+            ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t))
         }
-        _ => return None,
-    };
+    }
 
-    Some(iter::once(first_ty).chain(rest_tys))
+    fn def_id_is_local(&mut self, def_id: DefId) -> bool {
+        match self.in_crate {
+            InCrate::Local => def_id.is_local(),
+            InCrate::Remote => false,
+        }
+    }
 }
 
-fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
-    match in_crate {
-        // The type is local to *this* crate - it will not be
-        // local in any other crate.
-        InCrate::Remote => false,
-        InCrate::Local => def_id.is_local(),
-    }
+enum OrphanCheckEarlyExit<'tcx> {
+    ParamTy(Ty<'tcx>),
+    LocalTy(Ty<'tcx>),
 }
 
-fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
-    debug!("ty_is_local_constructor({:?})", ty);
-
-    match *ty.kind() {
-        ty::Bool
-        | ty::Char
-        | ty::Int(..)
-        | ty::Uint(..)
-        | ty::Float(..)
-        | ty::Str
-        | ty::FnDef(..)
-        | ty::FnPtr(_)
-        | ty::Array(..)
-        | ty::Slice(..)
-        | ty::RawPtr(..)
-        | ty::Ref(..)
-        | ty::Never
-        | ty::Tuple(..)
-        | ty::Param(..)
-        | ty::Projection(..) => false,
-
-        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate {
-            InCrate::Local => false,
-            // The inference variable might be unified with a local
-            // type in that remote crate.
-            InCrate::Remote => true,
-        },
-
-        ty::Adt(def, _) => def_id_is_local(def.did(), in_crate),
-        ty::Foreign(did) => def_id_is_local(did, in_crate),
-        ty::Opaque(..) => {
-            // This merits some explanation.
-            // Normally, opaque types are not involved when performing
-            // coherence checking, since it is illegal to directly
-            // implement a trait on an opaque type. However, we might
-            // end up looking at an opaque type during coherence checking
-            // if an opaque type gets used within another type (e.g. as
-            // a type parameter). This requires us to decide whether or
-            // not an opaque type should be considered 'local' or not.
-            //
-            // We choose to treat all opaque types as non-local, even
-            // those that appear within the same crate. This seems
-            // somewhat surprising at first, but makes sense when
-            // you consider that opaque types are supposed to hide
-            // the underlying type *within the same crate*. When an
-            // opaque type is used from outside the module
-            // where it is declared, it should be impossible to observe
-            // anything about it other than the traits that it implements.
-            //
-            // The alternative would be to look at the underlying type
-            // to determine whether or not the opaque type itself should
-            // be considered local. However, this could make it a breaking change
-            // to switch the underlying ('defining') type from a local type
-            // to a remote type. This would violate the rule that opaque
-            // types should be completely opaque apart from the traits
-            // that they implement, so we don't use this behavior.
-            false
-        }
+impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
+    type BreakTy = OrphanCheckEarlyExit<'tcx>;
+    fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        ControlFlow::CONTINUE
+    }
 
-        ty::Dynamic(ref tt, ..) => {
-            if let Some(principal) = tt.principal() {
-                def_id_is_local(principal.def_id(), in_crate)
-            } else {
-                false
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        let result = match *ty.kind() {
+            ty::Bool
+            | ty::Char
+            | ty::Int(..)
+            | ty::Uint(..)
+            | ty::Float(..)
+            | ty::Str
+            | ty::FnDef(..)
+            | ty::FnPtr(_)
+            | ty::Array(..)
+            | ty::Slice(..)
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Tuple(..)
+            | ty::Projection(..) => self.found_non_local_ty(ty),
+
+            ty::Param(..) => self.found_param_ty(ty),
+
+            ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate {
+                InCrate::Local => self.found_non_local_ty(ty),
+                // The inference variable might be unified with a local
+                // type in that remote crate.
+                InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+            },
+
+            // For fundamental types, we just look inside of them.
+            ty::Ref(_, ty, _) => ty.visit_with(self),
+            ty::Adt(def, substs) => {
+                if self.def_id_is_local(def.did()) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else if def.is_fundamental() {
+                    substs.visit_with(self)
+                } else {
+                    self.found_non_local_ty(ty)
+                }
             }
-        }
+            ty::Foreign(def_id) => {
+                if self.def_id_is_local(def_id) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::Dynamic(tt, ..) => {
+                let principal = tt.principal().map(|p| p.def_id());
+                if principal.map_or(false, |p| self.def_id_is_local(p)) {
+                    ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+                } else {
+                    self.found_non_local_ty(ty)
+                }
+            }
+            ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+            ty::Opaque(..) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+                self.tcx.sess.delay_span_bug(
+                    DUMMY_SP,
+                    format!("ty_is_local invoked on closure or generator: {:?}", ty),
+                );
+                ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+            }
+        };
+        // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
+        // the first type we visit is always the self type.
+        self.in_self_ty = false;
+        result
+    }
 
-        ty::Error(_) => true,
-
-        // These variants should never appear during coherence checking because they
-        // cannot be named directly.
-        //
-        // They could be indirectly used through an opaque type. While using opaque types
-        // in impls causes an error, this path can still be hit afterwards.
-        //
-        // See `test/ui/coherence/coherence-with-closure.rs` for an example where this
-        // could happens.
-        ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
-            tcx.sess.delay_span_bug(
-                DUMMY_SP,
-                format!("ty_is_local invoked on closure or generator: {:?}", ty),
-            );
-            true
-        }
+    // FIXME: Constants should participate in orphan checking.
+    fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        ControlFlow::CONTINUE
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index bca80e7ab8a..5636c74452c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -607,10 +607,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                 "{}, {}={}>",
                                 &constraint[..constraint.len() - 1],
                                 item.name,
-                                term.to_string()
+                                term
                             );
                         } else {
-                            constraint.push_str(&format!("<{}={}>", item.name, term.to_string()));
+                            constraint.push_str(&format!("<{}={}>", item.name, term));
                         }
                     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index fa2d2c751d9..17f34012d1d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -789,7 +789,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let mut param_env = obligation.param_env;
 
         fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| {
-            pred.remap_constness(self.tcx(), &mut param_env);
+            pred.remap_constness(&mut param_env);
             pred
         });
 
@@ -1321,7 +1321,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
         let tcx = self.tcx();
         let mut pred = cache_fresh_trait_pred.skip_binder();
-        pred.remap_constness(tcx, &mut param_env);
+        pred.remap_constness(&mut param_env);
 
         if self.can_use_global_caches(param_env) {
             if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) {
@@ -1375,7 +1375,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let tcx = self.tcx();
         let mut pred = cache_fresh_trait_pred.skip_binder();
 
-        pred.remap_constness(tcx, &mut param_env);
+        pred.remap_constness(&mut param_env);
 
         if !self.can_cache_candidate(&candidate) {
             debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable");
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 2d22e9bc76e..8e4cd2392e0 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1803,7 +1803,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .source_map()
                 .span_to_snippet(range_end.expr.span)
                 .map(|s| format!(" from `{s}`"))
-                .unwrap_or(String::new());
+                .unwrap_or_default();
             err.span_suggestion(
                 range_start.span.shrink_to_hi(),
                 &format!("to set the remaining fields{instead}, separate the last named field with a comma"),
@@ -2362,7 +2362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 false
             };
         let expr_snippet =
-            self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new());
+            self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or_default();
         let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')');
         let after_open = expr.span.lo() + rustc_span::BytePos(1);
         let before_close = expr.span.hi() - rustc_span::BytePos(1);
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 8aa8ac90b4c..1555f4f3fd6 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -481,6 +481,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.set_tainted_by_errors();
         let tcx = self.tcx;
 
+        // Get the argument span in the context of the call span so that
+        // suggestions and labels are (more) correct when an arg is a
+        // macro invocation.
+        let normalize_span = |span: Span| -> Span {
+            let normalized_span = span.find_ancestor_inside(error_span).unwrap_or(span);
+            // Sometimes macros mess up the spans, so do not normalize the
+            // arg span to equal the error span, because that's less useful
+            // than pointing out the arg expr in the wrong context.
+            if normalized_span.source_equal(error_span) { span } else { normalized_span }
+        };
+
         // Precompute the provided types and spans, since that's all we typically need for below
         let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args
             .iter()
@@ -490,7 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .borrow()
                     .expr_ty_adjusted_opt(*expr)
                     .unwrap_or_else(|| tcx.ty_error());
-                (self.resolve_vars_if_possible(ty), expr.span)
+                (self.resolve_vars_if_possible(ty), normalize_span(expr.span))
             })
             .collect();
         let callee_expr = match &call_expr.peel_blocks().kind {
@@ -600,11 +611,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Take some care with spans, so we don't suggest wrapping a macro's
                 // innards in parenthesis, for example.
                 if satisfied
-                    && let Some(lo) =
-                        provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span)
-                    && let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()]
-                        .span
-                        .find_ancestor_inside(error_span)
+                    && let Some((_, lo)) =
+                        provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx))
+                    && let Some((_, hi)) =
+                        provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1))
                 {
                     let mut err;
                     if tys.len() == 1 {
@@ -612,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // so don't do anything special here.
                         err = self.report_and_explain_type_error(
                             TypeTrace::types(
-                                &self.misc(lo),
+                                &self.misc(*lo),
                                 true,
                                 formal_and_expected_inputs[mismatch_idx.into()].1,
                                 provided_arg_tys[mismatch_idx.into()].0,
@@ -1052,7 +1062,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let suggestion_text = if let Some(provided_idx) = provided_idx
                     && let (_, provided_span) = provided_arg_tys[*provided_idx]
                     && let Ok(arg_text) =
-                        source_map.span_to_snippet(provided_span.source_callsite())
+                        source_map.span_to_snippet(provided_span)
                 {
                     arg_text
                 } else {
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
index fa4d7cb7723..ded0888c33e 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -72,9 +72,8 @@ impl<'tcx> ExprUseDelegate<'tcx> {
     }
 
     fn mark_consumed(&mut self, consumer: HirId, target: TrackedValue) {
-        if !self.places.consumed.contains_key(&consumer) {
-            self.places.consumed.insert(consumer, <_>::default());
-        }
+        self.places.consumed.entry(consumer).or_insert_with(|| <_>::default());
+
         debug!(?consumer, ?target, "mark_consumed");
         self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
     }
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 0bddd7a9906..cacbd54b6c2 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -178,6 +178,8 @@ pub struct BTreeMap<
     length: usize,
     /// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes).
     pub(super) alloc: ManuallyDrop<A>,
+    // For dropck; the `Box` avoids making the `Unpin` impl more strict than before
+    _marker: PhantomData<crate::boxed::Box<(K, V)>>,
 }
 
 #[stable(feature = "btree_drop", since = "1.7.0")]
@@ -187,6 +189,19 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V, A: Allocator + Clone> Drop for BTr
     }
 }
 
+// FIXME: This implementation is "wrong", but changing it would be a breaking change.
+// (The bounds of the automatic `UnwindSafe` implementation have been like this since Rust 1.50.)
+// Maybe we can fix it nonetheless with a crater run, or if the `UnwindSafe`
+// traits are deprecated, or disarmed (no longer causing hard errors) in the future.
+#[stable(feature = "btree_unwindsafe", since = "1.64.0")]
+impl<K, V, A: Allocator + Clone> core::panic::UnwindSafe for BTreeMap<K, V, A>
+where
+    A: core::panic::UnwindSafe,
+    K: core::panic::RefUnwindSafe,
+    V: core::panic::RefUnwindSafe,
+{
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K: Clone, V: Clone, A: Allocator + Clone> Clone for BTreeMap<K, V, A> {
     fn clone(&self) -> BTreeMap<K, V, A> {
@@ -204,6 +219,7 @@ impl<K: Clone, V: Clone, A: Allocator + Clone> Clone for BTreeMap<K, V, A> {
                         root: Some(Root::new(alloc.clone())),
                         length: 0,
                         alloc: ManuallyDrop::new(alloc),
+                        _marker: PhantomData,
                     };
 
                     {
@@ -567,7 +583,7 @@ impl<K, V> BTreeMap<K, V> {
     #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
     #[must_use]
     pub const fn new() -> BTreeMap<K, V> {
-        BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global) }
+        BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(Global), _marker: PhantomData }
     }
 }
 
@@ -593,6 +609,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
             root: mem::replace(&mut self.root, None),
             length: mem::replace(&mut self.length, 0),
             alloc: self.alloc.clone(),
+            _marker: PhantomData,
         });
     }
 
@@ -615,7 +632,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// ```
     #[unstable(feature = "btreemap_alloc", issue = "32838")]
     pub fn new_in(alloc: A) -> BTreeMap<K, V, A> {
-        BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc) }
+        BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc), _marker: PhantomData }
     }
 }
 
@@ -1320,7 +1337,12 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         let (new_left_len, right_len) = Root::calc_split_length(total_num, &left_root, &right_root);
         self.length = new_left_len;
 
-        BTreeMap { root: Some(right_root), length: right_len, alloc: self.alloc.clone() }
+        BTreeMap {
+            root: Some(right_root),
+            length: right_len,
+            alloc: self.alloc.clone(),
+            _marker: PhantomData,
+        }
     }
 
     /// Creates an iterator that visits all elements (key-value pairs) in
@@ -1445,7 +1467,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         let mut root = Root::new(alloc.clone());
         let mut length = 0;
         root.bulk_push(DedupSortedIter::new(iter.into_iter()), &mut length, alloc.clone());
-        BTreeMap { root: Some(root), length, alloc: ManuallyDrop::new(alloc) }
+        BTreeMap { root: Some(root), length, alloc: ManuallyDrop::new(alloc), _marker: PhantomData }
     }
 }
 
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index e34e26746c0..b1f5559dcfc 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -195,6 +195,41 @@ impl<B, C> ControlFlow<B, C> {
             ControlFlow::Break(x) => ControlFlow::Break(f(x)),
         }
     }
+
+    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
+    /// `ControlFlow` was `Continue` and `None` otherwise.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(control_flow_enum)]
+    /// use std::ops::ControlFlow;
+    ///
+    /// assert_eq!(ControlFlow::<i32, String>::Break(3).continue_value(), None);
+    /// assert_eq!(ControlFlow::<String, i32>::Continue(3).continue_value(), Some(3));
+    /// ```
+    #[inline]
+    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+    pub fn continue_value(self) -> Option<C> {
+        match self {
+            ControlFlow::Continue(x) => Some(x),
+            ControlFlow::Break(..) => None,
+        }
+    }
+
+    /// Maps `ControlFlow<B, C>` to `ControlFlow<B, T>` by applying a function
+    /// to the continue value in case it exists.
+    #[inline]
+    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+    pub fn map_continue<T, F>(self, f: F) -> ControlFlow<B, T>
+    where
+        F: FnOnce(C) -> T,
+    {
+        match self {
+            ControlFlow::Continue(x) => ControlFlow::Continue(f(x)),
+            ControlFlow::Break(x) => ControlFlow::Break(x),
+        }
+    }
 }
 
 /// These are used only as part of implementing the iterator adapters.
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index d661a13edc5..a463bc41db7 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -356,7 +356,7 @@ impl From<OwnedFd> for crate::net::UdpSocket {
     }
 }
 
-#[stable(feature = "io_safety", since = "1.63.0")]
+#[stable(feature = "asfd_ptrs", since = "1.64.0")]
 /// This impl allows implementing traits that require `AsFd` on Arc.
 /// ```
 /// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
@@ -379,7 +379,7 @@ impl<T: AsFd> AsFd for crate::sync::Arc<T> {
     }
 }
 
-#[stable(feature = "io_safety", since = "1.63.0")]
+#[stable(feature = "asfd_ptrs", since = "1.64.0")]
 impl<T: AsFd> AsFd for Box<T> {
     #[inline]
     fn as_fd(&self) -> BorrowedFd<'_> {
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs
index ab516a7f76d..8d5b540212a 100644
--- a/library/std/src/sys/unix/futex.rs
+++ b/library/std/src/sys/unix/futex.rs
@@ -240,17 +240,25 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 }
 
 #[cfg(target_os = "fuchsia")]
-mod zircon {
-    type zx_time_t = i64;
-    type zx_futex_t = crate::sync::atomic::AtomicU32;
-    type zx_handle_t = u32;
-    type zx_status_t = i32;
+pub mod zircon {
+    pub type zx_futex_t = crate::sync::atomic::AtomicU32;
+    pub type zx_handle_t = u32;
+    pub type zx_status_t = i32;
+    pub type zx_time_t = i64;
 
     pub const ZX_HANDLE_INVALID: zx_handle_t = 0;
-    pub const ZX_ERR_TIMED_OUT: zx_status_t = -21;
+
     pub const ZX_TIME_INFINITE: zx_time_t = zx_time_t::MAX;
 
+    pub const ZX_OK: zx_status_t = 0;
+    pub const ZX_ERR_INVALID_ARGS: zx_status_t = -10;
+    pub const ZX_ERR_BAD_HANDLE: zx_status_t = -11;
+    pub const ZX_ERR_WRONG_TYPE: zx_status_t = -12;
+    pub const ZX_ERR_BAD_STATE: zx_status_t = -20;
+    pub const ZX_ERR_TIMED_OUT: zx_status_t = -21;
+
     extern "C" {
+        pub fn zx_clock_get_monotonic() -> zx_time_t;
         pub fn zx_futex_wait(
             value_ptr: *const zx_futex_t,
             current_value: zx_futex_t,
@@ -258,7 +266,8 @@ mod zircon {
             deadline: zx_time_t,
         ) -> zx_status_t;
         pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t;
-        pub fn zx_clock_get_monotonic() -> zx_time_t;
+        pub fn zx_futex_wake_single_owner(value_ptr: *const zx_futex_t) -> zx_status_t;
+        pub fn zx_thread_self() -> zx_handle_t;
     }
 }
 
@@ -287,3 +296,8 @@ pub fn futex_wake(futex: &AtomicU32) -> bool {
     unsafe { zircon::zx_futex_wake(futex, 1) };
     false
 }
+
+#[cfg(target_os = "fuchsia")]
+pub fn futex_wake_all(futex: &AtomicU32) {
+    unsafe { zircon::zx_futex_wake(futex, u32::MAX) };
+}
diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs
new file mode 100644
index 00000000000..ce427599c3b
--- /dev/null
+++ b/library/std/src/sys/unix/locks/fuchsia_mutex.rs
@@ -0,0 +1,165 @@
+//! A priority inheriting mutex for Fuchsia.
+//!
+//! This is a port of the [mutex in Fuchsia's libsync]. Contrary to the original,
+//! it does not abort the process when reentrant locking is detected, but deadlocks.
+//!
+//! Priority inheritance is achieved by storing the owning thread's handle in an
+//! atomic variable. Fuchsia's futex operations support setting an owner thread
+//! for a futex, which can boost that thread's priority while the futex is waited
+//! upon.
+//!
+//! libsync is licenced under the following BSD-style licence:
+//!
+//! Copyright 2016 The Fuchsia Authors.
+//!
+//! Redistribution and use in source and binary forms, with or without
+//! modification, are permitted provided that the following conditions are
+//! met:
+//!
+//!    * Redistributions of source code must retain the above copyright
+//!      notice, this list of conditions and the following disclaimer.
+//!    * Redistributions in binary form must reproduce the above
+//!      copyright notice, this list of conditions and the following
+//!      disclaimer in the documentation and/or other materials provided
+//!      with the distribution.
+//!
+//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+//! A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+//! OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+//! LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+//! DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+//! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//! (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+//! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//!
+//! [mutex in Fuchsia's libsync]: https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/ulib/sync/mutex.c
+
+use crate::sync::atomic::{
+    AtomicU32,
+    Ordering::{Acquire, Relaxed, Release},
+};
+use crate::sys::futex::zircon::{
+    zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t, zx_thread_self, ZX_ERR_BAD_HANDLE,
+    ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE, ZX_OK,
+    ZX_TIME_INFINITE,
+};
+
+// The lowest two bits of a `zx_handle_t` are always set, so the lowest bit is used to mark the
+// mutex as contested by clearing it.
+const CONTESTED_BIT: u32 = 1;
+// This can never be a valid `zx_handle_t`.
+const UNLOCKED: u32 = 0;
+
+pub type MovableMutex = Mutex;
+
+pub struct Mutex {
+    futex: AtomicU32,
+}
+
+#[inline]
+fn to_state(owner: zx_handle_t) -> u32 {
+    owner
+}
+
+#[inline]
+fn to_owner(state: u32) -> zx_handle_t {
+    state | CONTESTED_BIT
+}
+
+#[inline]
+fn is_contested(state: u32) -> bool {
+    state & CONTESTED_BIT == 0
+}
+
+#[inline]
+fn mark_contested(state: u32) -> u32 {
+    state & !CONTESTED_BIT
+}
+
+impl Mutex {
+    #[inline]
+    pub const fn new() -> Mutex {
+        Mutex { futex: AtomicU32::new(UNLOCKED) }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {}
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        let thread_self = zx_thread_self();
+        self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed).is_ok()
+    }
+
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let thread_self = zx_thread_self();
+        if let Err(state) =
+            self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed)
+        {
+            self.lock_contested(state, thread_self);
+        }
+    }
+
+    #[cold]
+    fn lock_contested(&self, mut state: u32, thread_self: zx_handle_t) {
+        let owned_state = mark_contested(to_state(thread_self));
+        loop {
+            // Mark the mutex as contested if it is not already.
+            let contested = mark_contested(state);
+            if is_contested(state)
+                || self.futex.compare_exchange(state, contested, Relaxed, Relaxed).is_ok()
+            {
+                // The mutex has been marked as contested, wait for the state to change.
+                unsafe {
+                    match zx_futex_wait(
+                        &self.futex,
+                        AtomicU32::new(contested),
+                        to_owner(state),
+                        ZX_TIME_INFINITE,
+                    ) {
+                        ZX_OK | ZX_ERR_BAD_STATE | ZX_ERR_TIMED_OUT => (),
+                        // Note that if a thread handle is reused after its associated thread
+                        // exits without unlocking the mutex, an arbitrary thread's priority
+                        // could be boosted by the wait, but there is currently no way to
+                        // prevent that.
+                        ZX_ERR_INVALID_ARGS | ZX_ERR_BAD_HANDLE | ZX_ERR_WRONG_TYPE => {
+                            panic!(
+                                "either the current thread is trying to lock a mutex it has
+                                already locked, or the previous owner did not unlock the mutex
+                                before exiting"
+                            )
+                        }
+                        error => panic!("unexpected error in zx_futex_wait: {error}"),
+                    }
+                }
+            }
+
+            // The state has changed or a wakeup occured, try to lock the mutex.
+            match self.futex.compare_exchange(UNLOCKED, owned_state, Acquire, Relaxed) {
+                Ok(_) => return,
+                Err(updated) => state = updated,
+            }
+        }
+    }
+
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        if is_contested(self.futex.swap(UNLOCKED, Release)) {
+            // The woken thread will mark the mutex as contested again,
+            // and return here, waking until there are no waiters left,
+            // in which case this is a noop.
+            self.wake();
+        }
+    }
+
+    #[cold]
+    fn wake(&self) {
+        unsafe {
+            zx_futex_wake_single_owner(&self.futex);
+        }
+    }
+}
diff --git a/library/std/src/sys/unix/locks/futex_condvar.rs b/library/std/src/sys/unix/locks/futex_condvar.rs
new file mode 100644
index 00000000000..c0576c17880
--- /dev/null
+++ b/library/std/src/sys/unix/locks/futex_condvar.rs
@@ -0,0 +1,58 @@
+use super::Mutex;
+use crate::sync::atomic::{AtomicU32, Ordering::Relaxed};
+use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
+use crate::time::Duration;
+
+pub type MovableCondvar = Condvar;
+
+pub struct Condvar {
+    // The value of this atomic is simply incremented on every notification.
+    // This is used by `.wait()` to not miss any notifications after
+    // unlocking the mutex and before waiting for notifications.
+    futex: AtomicU32,
+}
+
+impl Condvar {
+    #[inline]
+    pub const fn new() -> Self {
+        Self { futex: AtomicU32::new(0) }
+    }
+
+    // All the memory orderings here are `Relaxed`,
+    // because synchronization is done by unlocking and locking the mutex.
+
+    pub unsafe fn notify_one(&self) {
+        self.futex.fetch_add(1, Relaxed);
+        futex_wake(&self.futex);
+    }
+
+    pub unsafe fn notify_all(&self) {
+        self.futex.fetch_add(1, Relaxed);
+        futex_wake_all(&self.futex);
+    }
+
+    pub unsafe fn wait(&self, mutex: &Mutex) {
+        self.wait_optional_timeout(mutex, None);
+    }
+
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, timeout: Duration) -> bool {
+        self.wait_optional_timeout(mutex, Some(timeout))
+    }
+
+    unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option<Duration>) -> bool {
+        // Examine the notification counter _before_ we unlock the mutex.
+        let futex_value = self.futex.load(Relaxed);
+
+        // Unlock the mutex before going to sleep.
+        mutex.unlock();
+
+        // Wait, but only if there hasn't been any
+        // notification since we unlocked the mutex.
+        let r = futex_wait(&self.futex, futex_value, timeout);
+
+        // Lock the mutex again.
+        mutex.lock();
+
+        r
+    }
+}
diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex_mutex.rs
index a9a1a32c5af..99ba86e5f99 100644
--- a/library/std/src/sys/unix/locks/futex.rs
+++ b/library/std/src/sys/unix/locks/futex_mutex.rs
@@ -2,11 +2,9 @@ use crate::sync::atomic::{
     AtomicU32,
     Ordering::{Acquire, Relaxed, Release},
 };
-use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
-use crate::time::Duration;
+use crate::sys::futex::{futex_wait, futex_wake};
 
 pub type MovableMutex = Mutex;
-pub type MovableCondvar = Condvar;
 
 pub struct Mutex {
     /// 0: unlocked
@@ -101,55 +99,3 @@ impl Mutex {
         futex_wake(&self.futex);
     }
 }
-
-pub struct Condvar {
-    // The value of this atomic is simply incremented on every notification.
-    // This is used by `.wait()` to not miss any notifications after
-    // unlocking the mutex and before waiting for notifications.
-    futex: AtomicU32,
-}
-
-impl Condvar {
-    #[inline]
-    pub const fn new() -> Self {
-        Self { futex: AtomicU32::new(0) }
-    }
-
-    // All the memory orderings here are `Relaxed`,
-    // because synchronization is done by unlocking and locking the mutex.
-
-    pub unsafe fn notify_one(&self) {
-        self.futex.fetch_add(1, Relaxed);
-        futex_wake(&self.futex);
-    }
-
-    pub unsafe fn notify_all(&self) {
-        self.futex.fetch_add(1, Relaxed);
-        futex_wake_all(&self.futex);
-    }
-
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        self.wait_optional_timeout(mutex, None);
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, timeout: Duration) -> bool {
-        self.wait_optional_timeout(mutex, Some(timeout))
-    }
-
-    unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option<Duration>) -> bool {
-        // Examine the notification counter _before_ we unlock the mutex.
-        let futex_value = self.futex.load(Relaxed);
-
-        // Unlock the mutex before going to sleep.
-        mutex.unlock();
-
-        // Wait, but only if there hasn't been any
-        // notification since we unlocked the mutex.
-        let r = futex_wait(&self.futex, futex_value, timeout);
-
-        // Lock the mutex again.
-        mutex.lock();
-
-        r
-    }
-}
diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs
index 03400efa3c9..f5f92f69358 100644
--- a/library/std/src/sys/unix/locks/mod.rs
+++ b/library/std/src/sys/unix/locks/mod.rs
@@ -7,10 +7,19 @@ cfg_if::cfg_if! {
         target_os = "openbsd",
         target_os = "dragonfly",
     ))] {
-        mod futex;
+        mod futex_mutex;
         mod futex_rwlock;
-        pub(crate) use futex::{Mutex, MovableMutex, MovableCondvar};
+        mod futex_condvar;
+        pub(crate) use futex_mutex::{Mutex, MovableMutex};
         pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use futex_condvar::MovableCondvar;
+    } else if #[cfg(target_os = "fuchsia")] {
+        mod fuchsia_mutex;
+        mod futex_rwlock;
+        mod futex_condvar;
+        pub(crate) use fuchsia_mutex::{Mutex, MovableMutex};
+        pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
+        pub(crate) use futex_condvar::MovableCondvar;
     } else {
         mod pthread_mutex;
         mod pthread_rwlock;
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 8c08f776679..4dd79af5630 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -496,8 +496,7 @@ impl Item {
         // Primitives and Keywords are written in the source code as private modules.
         // The modules need to be private so that nobody actually uses them, but the
         // keywords and primitives that they are documenting are public.
-        let visibility = if matches!(&kind, ItemKind::KeywordItem(..) | ItemKind::PrimitiveItem(..))
-        {
+        let visibility = if matches!(&kind, ItemKind::KeywordItem | ItemKind::PrimitiveItem(..)) {
             Visibility::Public
         } else {
             cx.tcx.visibility(def_id).clean(cx)
@@ -769,7 +768,7 @@ pub(crate) enum ItemKind {
     AssocTypeItem(Typedef, Vec<GenericBound>),
     /// An item that has been stripped by a rustdoc pass
     StrippedItem(Box<ItemKind>),
-    KeywordItem(Symbol),
+    KeywordItem,
 }
 
 impl ItemKind {
@@ -808,7 +807,7 @@ impl ItemKind {
             | TyAssocTypeItem(..)
             | AssocTypeItem(..)
             | StrippedItem(_)
-            | KeywordItem(_) => [].iter(),
+            | KeywordItem => [].iter(),
         }
     }
 }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 22b1e2335fd..fa449a21b0c 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -69,7 +69,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
             )
         }));
         m.items.extend(keywords.into_iter().map(|(def_id, kw)| {
-            Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem(kw), cx)
+            Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem, cx)
         }));
     }
 
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index 336448904d1..c93897236db 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -69,7 +69,7 @@ pub(crate) trait DocFolder: Sized {
             | AssocConstItem(..)
             | TyAssocTypeItem(..)
             | AssocTypeItem(..)
-            | KeywordItem(_) => kind,
+            | KeywordItem => kind,
         }
     }
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index d7276a427c4..b9774eb70ea 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -413,7 +413,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             | clean::TyAssocTypeItem(..)
             | clean::AssocTypeItem(..)
             | clean::StrippedItem(..)
-            | clean::KeywordItem(..) => {
+            | clean::KeywordItem => {
                 // FIXME: Do these need handling?
                 // The person writing this comment doesn't know.
                 // So would rather leave them to an expert,
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index 9cb3327d7c7..0a7ee200591 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -91,7 +91,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
             clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst,
             clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
             clean::ForeignTypeItem => ItemType::ForeignType,
-            clean::KeywordItem(..) => ItemType::Keyword,
+            clean::KeywordItem => ItemType::Keyword,
             clean::TraitAliasItem(..) => ItemType::TraitAlias,
             clean::ProcMacroItem(ref mac) => match mac.kind {
                 MacroKind::Bang => ItemType::Macro,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index daacc57a55a..0cee114b346 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -104,7 +104,7 @@ pub(super) fn print_item(
         clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ",
         clean::ConstantItem(..) => "Constant ",
         clean::ForeignTypeItem => "Foreign Type ",
-        clean::KeywordItem(..) => "Keyword ",
+        clean::KeywordItem => "Keyword ",
         clean::OpaqueTyItem(..) => "Opaque Type ",
         clean::TraitAliasItem(..) => "Trait Alias ",
         _ => {
@@ -175,7 +175,7 @@ pub(super) fn print_item(
         clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i),
         clean::ConstantItem(ref c) => item_constant(buf, cx, item, c),
         clean::ForeignTypeItem => item_foreign_type(buf, cx, item),
-        clean::KeywordItem(_) => item_keyword(buf, cx, item),
+        clean::KeywordItem => item_keyword(buf, cx, item),
         clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e),
         clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta),
         _ => {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 9000ab472d9..418d7c83535 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -43,7 +43,7 @@ impl JsonRenderer<'_> {
         let span = item.span(self.tcx);
         let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item;
         let inner = match *item.kind {
-            clean::KeywordItem(_) => return None,
+            clean::KeywordItem => return None,
             clean::StrippedItem(ref inner) => {
                 match &**inner {
                     // We document non-empty stripped modules as with `Module::is_stripped` set to
@@ -269,7 +269,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
             default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
         },
         // `convert_item` early returns `None` for stripped items and keywords.
-        KeywordItem(_) => unreachable!(),
+        KeywordItem => unreachable!(),
         StrippedItem(inner) => {
             match *inner {
                 ModuleItem(m) => ItemEnum::Module(Module {
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 735a077fe1f..e80a94fe749 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -69,7 +69,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
                 | clean::ExternCrateItem { .. }
                 | clean::ImportItem(_)
                 | clean::PrimitiveItem(_)
-                | clean::KeywordItem(_)
+                | clean::KeywordItem
                 // check for trait impl
                 | clean::ImplItem(clean::Impl { trait_: Some(_), .. })
         )
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 5f2f50e712b..0d419042a10 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -98,7 +98,7 @@ impl<'a> DocFolder for Stripper<'a> {
             clean::PrimitiveItem(..) => {}
 
             // Keywords are never stripped
-            clean::KeywordItem(..) => {}
+            clean::KeywordItem => {}
         }
 
         let fastreturn = match *i.kind {
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index 75e1dd41a63..0bb41977c97 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -43,7 +43,7 @@ pub(crate) trait DocVisitor: Sized {
             | AssocConstItem(..)
             | TyAssocTypeItem(..)
             | AssocTypeItem(..)
-            | KeywordItem(_) => {}
+            | KeywordItem => {}
         }
     }
 
diff --git a/src/test/ui/btreemap/btreemap_dropck.rs b/src/test/ui/btreemap/btreemap_dropck.rs
new file mode 100644
index 00000000000..c58727df30c
--- /dev/null
+++ b/src/test/ui/btreemap/btreemap_dropck.rs
@@ -0,0 +1,16 @@
+struct PrintOnDrop<'a>(&'a str);
+
+impl Drop for PrintOnDrop<'_> {
+    fn drop(&mut self) {
+        println!("printint: {}", self.0);
+    }
+}
+
+use std::collections::BTreeMap;
+use std::iter::FromIterator;
+
+fn main() {
+    let s = String::from("Hello World!");
+    let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]);
+    drop(s); //~ ERROR cannot move out of `s` because it is borrowed
+}
diff --git a/src/test/ui/btreemap/btreemap_dropck.stderr b/src/test/ui/btreemap/btreemap_dropck.stderr
new file mode 100644
index 00000000000..e953e7ae82b
--- /dev/null
+++ b/src/test/ui/btreemap/btreemap_dropck.stderr
@@ -0,0 +1,13 @@
+error[E0505]: cannot move out of `s` because it is borrowed
+  --> $DIR/btreemap_dropck.rs:15:10
+   |
+LL |     let _map = BTreeMap::from_iter([((), PrintOnDrop(&s))]);
+   |                                                      -- borrow of `s` occurs here
+LL |     drop(s);
+   |          ^ move out of `s` occurs here
+LL | }
+   | - borrow might be used here, when `_map` is dropped and runs the `Drop` code for type `BTreeMap`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/generator/issue-52304.rs b/src/test/ui/generator/issue-52304.rs
new file mode 100644
index 00000000000..3e9de765b12
--- /dev/null
+++ b/src/test/ui/generator/issue-52304.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+pub fn example() -> impl Generator {
+    || yield &1
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr
index 479b451855d..2eea726a19c 100644
--- a/src/test/ui/impl-trait/negative-reasoning.stderr
+++ b/src/test/ui/impl-trait/negative-reasoning.stderr
@@ -7,7 +7,7 @@ LL | impl<T: std::fmt::Debug> AnotherTrait for T {}
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
    |
-   = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
+   = note: downstream crates may implement trait `std::fmt::Debug` for type `OpaqueType`
 
 error: cannot implement trait on type alias impl trait
   --> $DIR/negative-reasoning.rs:19:25
diff --git a/src/test/ui/inference/deref-suggestion.rs b/src/test/ui/inference/deref-suggestion.rs
index 4fd695585ba..0d8e7289dc8 100644
--- a/src/test/ui/inference/deref-suggestion.rs
+++ b/src/test/ui/inference/deref-suggestion.rs
@@ -1,5 +1,5 @@
 macro_rules! borrow {
-    ($x:expr) => { &$x } //~ ERROR mismatched types
+    ($x:expr) => { &$x }
 }
 
 fn foo(_: String) {}
@@ -32,6 +32,7 @@ fn main() {
     foo(&mut "aaa".to_owned());
     //~^ ERROR mismatched types
     foo3(borrow!(0));
+    //~^ ERROR mismatched types
     foo4(&0);
     assert_eq!(3i32, &3i32);
     //~^ ERROR mismatched types
diff --git a/src/test/ui/inference/deref-suggestion.stderr b/src/test/ui/inference/deref-suggestion.stderr
index e763e17e517..d729f2d682a 100644
--- a/src/test/ui/inference/deref-suggestion.stderr
+++ b/src/test/ui/inference/deref-suggestion.stderr
@@ -70,13 +70,10 @@ LL +     foo("aaa".to_owned());
    |
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:2:20
+  --> $DIR/deref-suggestion.rs:34:10
    |
-LL |     ($x:expr) => { &$x }
-   |                    ^^^ expected `u32`, found `&{integer}`
-...
 LL |     foo3(borrow!(0));
-   |     ---- ---------- in this macro invocation
+   |     ---- ^^^^^^^^^^ expected `u32`, found `&{integer}`
    |     |
    |     arguments to this function are incorrect
    |
@@ -85,10 +82,9 @@ note: function defined here
    |
 LL | fn foo3(_: u32) {}
    |    ^^^^ ------
-   = note: this error originates in the macro `borrow` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:36:5
+  --> $DIR/deref-suggestion.rs:37:5
    |
 LL |     assert_eq!(3i32, &3i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `&i32`
@@ -96,7 +92,7 @@ LL |     assert_eq!(3i32, &3i32);
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:39:17
+  --> $DIR/deref-suggestion.rs:40:17
    |
 LL |     let s = S { u };
    |                 ^
@@ -105,7 +101,7 @@ LL |     let s = S { u };
    |                 help: consider borrowing here: `u: &u`
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:41:20
+  --> $DIR/deref-suggestion.rs:42:20
    |
 LL |     let s = S { u: u };
    |                    ^
@@ -114,7 +110,7 @@ LL |     let s = S { u: u };
    |                    help: consider borrowing here: `&u`
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:44:17
+  --> $DIR/deref-suggestion.rs:45:17
    |
 LL |     let r = R { i };
    |                 ^ expected `u32`, found `&{integer}`
@@ -125,7 +121,7 @@ LL |     let r = R { i: *i };
    |                 ++++
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:46:20
+  --> $DIR/deref-suggestion.rs:47:20
    |
 LL |     let r = R { i: i };
    |                    ^ expected `u32`, found `&{integer}`
@@ -136,7 +132,7 @@ LL |     let r = R { i: *i };
    |                    +
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:55:9
+  --> $DIR/deref-suggestion.rs:56:9
    |
 LL |         b
    |         ^ expected `i32`, found `&{integer}`
@@ -147,7 +143,7 @@ LL |         *b
    |         +
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:63:9
+  --> $DIR/deref-suggestion.rs:64:9
    |
 LL |         b
    |         ^ expected `i32`, found `&{integer}`
@@ -158,7 +154,7 @@ LL |         *b
    |         +
 
 error[E0308]: `if` and `else` have incompatible types
-  --> $DIR/deref-suggestion.rs:68:12
+  --> $DIR/deref-suggestion.rs:69:12
    |
 LL |        let val = if true {
    |   _______________-
diff --git a/src/test/ui/issues/issue-72554.rs b/src/test/ui/issues/issue-72554.rs
index 47aca05d778..7287639c61d 100644
--- a/src/test/ui/issues/issue-72554.rs
+++ b/src/test/ui/issues/issue-72554.rs
@@ -1,10 +1,13 @@
 use std::collections::BTreeSet;
 
 #[derive(Hash)]
-pub enum ElemDerived { //~ ERROR recursive type `ElemDerived` has infinite size
+pub enum ElemDerived {
+    //~^ ERROR recursive type `ElemDerived` has infinite size
+    //~| ERROR cycle detected when computing drop-check constraints for `ElemDerived`
     A(ElemDerived)
 }
 
+
 pub enum Elem {
     Derived(ElemDerived)
 }
diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr
index a6e44be636a..3e5adcae133 100644
--- a/src/test/ui/issues/issue-72554.stderr
+++ b/src/test/ui/issues/issue-72554.stderr
@@ -3,6 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size
    |
 LL | pub enum ElemDerived {
    | ^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size
+...
 LL |     A(ElemDerived)
    |       ----------- recursive without indirection
    |
@@ -11,6 +12,20 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ElemDerived
 LL |     A(Box<ElemDerived>)
    |       ++++           +
 
-error: aborting due to previous error
+error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived`
+  --> $DIR/issue-72554.rs:4:1
+   |
+LL | pub enum ElemDerived {
+   | ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again
+note: cycle used when computing drop-check constraints for `Elem`
+  --> $DIR/issue-72554.rs:11:1
+   |
+LL | pub enum Elem {
+   | ^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0072`.
+Some errors have detailed explanations: E0072, E0391.
+For more information about an error, try `rustc --explain E0072`.