about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-21 20:56:38 +0000
committerbors <bors@rust-lang.org>2023-03-21 20:56:38 +0000
commit1db9c061d387a66ab16a90ec5a1b90adf216e2da (patch)
tree7e7a041d9e2da492fd9b6ad2170afa4948a3f0ff
parent77d50a8870a912af1def75760b9638db892717c5 (diff)
parent94d2028abd638366d338c8f24981240415129c90 (diff)
downloadrust-1db9c061d387a66ab16a90ec5a1b90adf216e2da.tar.gz
rust-1db9c061d387a66ab16a90ec5a1b90adf216e2da.zip
Auto merge of #109453 - matthiaskrgr:rollup-odn02wu, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #96391 (Windows: make `Command` prefer non-verbatim paths)
 - #108164 (Drop all messages in bounded channel when destroying the last receiver)
 - #108729 (fix: modify the condition that `resolve_imports` stops)
 - #109336 (Constrain const vars to error if const types are mismatched)
 - #109403 (Avoid ICE of attempt to add with overflow in emitter)
 - #109415 (Refactor `handle_missing_lit`.)
 - #109441 (Only implement Fn* traits for extern "Rust" safe function pointers and items)
 - #109446 (Do not suggest bounds restrictions for synthesized RPITITs)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_errors/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs17
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs14
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs22
-rw-r--r--compiler/rustc_resolve/src/imports.rs38
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs6
-rw-r--r--library/std/src/sync/mpmc/array.rs107
-rw-r--r--library/std/src/sync/mpmc/mod.rs4
-rw-r--r--library/std/src/sync/mpsc/sync_tests.rs13
-rw-r--r--library/std/src/sys/windows/args.rs23
-rw-r--r--library/std/src/sys/windows/path.rs65
-rw-r--r--library/std/src/sys/windows/process.rs12
-rw-r--r--tests/ui/async-await/in-trait/missing-send-bound.current.stderr (renamed from tests/ui/async-await/in-trait/missing-send-bound.stderr)8
-rw-r--r--tests/ui/async-await/in-trait/missing-send-bound.next.stderr29
-rw-r--r--tests/ui/async-await/in-trait/missing-send-bound.rs2
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.rs13
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.stderr9
-rw-r--r--tests/ui/macros/nested-use-as.rs83
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs4
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr15
-rw-r--r--tests/ui/suggestions/issue-109396.rs12
-rw-r--r--tests/ui/suggestions/issue-109396.stderr34
-rw-r--r--tests/ui/traits/new-solver/fn-trait.rs21
-rw-r--r--tests/ui/traits/new-solver/fn-trait.stderr124
27 files changed, 597 insertions, 139 deletions
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index bab4f31e777..9866a9bffe0 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -331,7 +331,7 @@ impl CodeSuggestion {
                     });
                     buf.push_str(&part.snippet);
                     let cur_hi = sm.lookup_char_pos(part.span.hi());
-                    if cur_hi.line == cur_lo.line {
+                    if cur_hi.line == cur_lo.line && !part.snippet.is_empty() {
                         // Account for the difference between the width of the current code and the
                         // snippet being suggested, so that the *later* suggestions are correctly
                         // aligned on the screen.
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index bb6fdd2ffc2..4503af03ca3 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -189,10 +189,19 @@ impl<'tcx> InferCtxt<'tcx> {
         // the expected const's type. Specifically, we don't want const infer vars
         // to do any type shapeshifting before and after resolution.
         if let Err(guar) = compatible_types {
-            return Ok(self.tcx.const_error_with_guaranteed(
-                if relation.a_is_expected() { a.ty() } else { b.ty() },
-                guar,
-            ));
+            // HACK: equating both sides with `[const error]` eagerly prevents us
+            // from leaving unconstrained inference vars during things like impl
+            // matching in the solver.
+            let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar);
+            if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
+                return self.unify_const_variable(vid, a_error);
+            }
+            let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar);
+            if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
+                return self.unify_const_variable(vid, b_error);
+            }
+
+            return Ok(if relation.a_is_expected() { a_error } else { b_error });
         }
 
         match (a.kind(), b.kind()) {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 4c606b939b2..2a0536a1af7 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -23,7 +23,7 @@ use rustc_macros::HashStable;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
-use rustc_target::spec::abi;
+use rustc_target::spec::abi::{self, Abi};
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::fmt;
@@ -1403,6 +1403,18 @@ impl<'tcx> PolyFnSig<'tcx> {
     pub fn abi(&self) -> abi::Abi {
         self.skip_binder().abi
     }
+
+    pub fn is_fn_trait_compatible(&self) -> bool {
+        matches!(
+            self.skip_binder(),
+            ty::FnSig {
+                unsafety: rustc_hir::Unsafety::Normal,
+                abi: Abi::Rust,
+                c_variadic: false,
+                ..
+            }
+        )
+    }
 }
 
 pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 296eb4d653c..8b69b3cb036 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1843,20 +1843,14 @@ impl<'a> Parser<'a> {
         &mut self,
         mk_lit_char: impl FnOnce(Symbol, Span) -> L,
     ) -> PResult<'a, L> {
-        if let token::Interpolated(inner) = &self.token.kind {
-            let expr = match inner.as_ref() {
-                token::NtExpr(expr) => Some(expr),
-                token::NtLiteral(expr) => Some(expr),
-                _ => None,
-            };
-            if let Some(expr) = expr {
-                if matches!(expr.kind, ExprKind::Err) {
-                    let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
-                        .into_diagnostic(&self.sess.span_diagnostic);
-                    err.downgrade_to_delayed_bug();
-                    return Err(err);
-                }
-            }
+        if let token::Interpolated(nt) = &self.token.kind
+            && let token::NtExpr(e) | token::NtLiteral(e) = &**nt
+            && matches!(e.kind, ExprKind::Err)
+        {
+            let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
+                .into_diagnostic(&self.sess.span_diagnostic);
+            err.downgrade_to_delayed_bug();
+            return Err(err);
         }
         let token = self.token.clone();
         let err = |self_: &Self| {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 6e27bcc5bf3..4d4bc1be349 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -423,13 +423,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     /// Resolves all imports for the crate. This method performs the fixed-
     /// point iteration.
     pub(crate) fn resolve_imports(&mut self) {
-        let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
-        while self.indeterminate_imports.len() < prev_num_indeterminates {
-            prev_num_indeterminates = self.indeterminate_imports.len();
+        let mut prev_indeterminate_count = usize::MAX;
+        let mut indeterminate_count = self.indeterminate_imports.len() * 3;
+        while indeterminate_count < prev_indeterminate_count {
+            prev_indeterminate_count = indeterminate_count;
+            indeterminate_count = 0;
             for import in mem::take(&mut self.indeterminate_imports) {
-                match self.resolve_import(&import) {
-                    true => self.determined_imports.push(import),
-                    false => self.indeterminate_imports.push(import),
+                let import_indeterminate_count = self.resolve_import(&import);
+                indeterminate_count += import_indeterminate_count;
+                match import_indeterminate_count {
+                    0 => self.determined_imports.push(import),
+                    _ => self.indeterminate_imports.push(import),
                 }
             }
         }
@@ -581,9 +585,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         diag.emit();
     }
 
-    /// Attempts to resolve the given import, returning true if its resolution is determined.
-    /// If successful, the resolved bindings are written into the module.
-    fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
+    /// Attempts to resolve the given import, returning:
+    /// - `0` means its resolution is determined.
+    /// - Other values mean that indeterminate exists under certain namespaces.
+    ///
+    /// Meanwhile, if resolve successful, the resolved bindings are written
+    /// into the module.
+    fn resolve_import(&mut self, import: &'a Import<'a>) -> usize {
         debug!(
             "(resolving import for module) resolving import `{}::...` in `{}`",
             Segment::names_to_string(&import.module_path),
@@ -601,8 +609,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
             match path_res {
                 PathResult::Module(module) => module,
-                PathResult::Indeterminate => return false,
-                PathResult::NonModule(..) | PathResult::Failed { .. } => return true,
+                PathResult::Indeterminate => return 3,
+                PathResult::NonModule(..) | PathResult::Failed { .. } => return 0,
             }
         };
 
@@ -618,12 +626,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             } => (source, target, source_bindings, target_bindings, type_ns_only),
             ImportKind::Glob { .. } => {
                 self.resolve_glob_import(import);
-                return true;
+                return 0;
             }
             _ => unreachable!(),
         };
 
-        let mut indeterminate = false;
+        let mut indeterminate_count = 0;
         self.per_ns(|this, ns| {
             if !type_ns_only || ns == TypeNS {
                 if let Err(Undetermined) = source_bindings[ns].get() {
@@ -646,7 +654,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
                 let parent = import.parent_scope.module;
                 match source_bindings[ns].get() {
-                    Err(Undetermined) => indeterminate = true,
+                    Err(Undetermined) => indeterminate_count += 1,
                     // Don't update the resolution, because it was never added.
                     Err(Determined) if target.name == kw::Underscore => {}
                     Ok(binding) if binding.is_importable() => {
@@ -670,7 +678,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
         });
 
-        !indeterminate
+        indeterminate_count
     }
 
     /// Performs final import resolution, consistency checks and error reporting.
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
index 871e7c2cc5a..9817186b874 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
@@ -189,12 +189,28 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
     goal_kind: ty::ClosureKind,
 ) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> {
     match *self_ty.kind() {
-        ty::FnDef(def_id, substs) => Ok(Some(
-            tcx.fn_sig(def_id)
-                .subst(tcx, substs)
-                .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
-        )),
-        ty::FnPtr(sig) => Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))),
+        // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
+        ty::FnDef(def_id, substs) => {
+            let sig = tcx.fn_sig(def_id);
+            if sig.skip_binder().is_fn_trait_compatible()
+                && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+            {
+                Ok(Some(
+                    sig.subst(tcx, substs)
+                        .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
+                ))
+            } else {
+                Err(NoSolution)
+            }
+        }
+        // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
+        ty::FnPtr(sig) => {
+            if sig.is_fn_trait_compatible() {
+                Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output()))))
+            } else {
+                Err(NoSolution)
+            }
+        }
         ty::Closure(_, substs) => {
             let closure_substs = substs.as_closure();
             match closure_substs.kind_ty().to_opt_closure_kind() {
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 186bfc701bc..b501840b926 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -420,6 +420,7 @@ fn suggest_restriction<'tcx>(
 ) {
     if hir_generics.where_clause_span.from_expansion()
         || hir_generics.where_clause_span.desugaring_kind().is_some()
+        || projection.map_or(false, |projection| tcx.opt_rpitit_info(projection.def_id).is_some())
     {
         return;
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 3182af989f0..e06eff34df2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -11,7 +11,6 @@ use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
 use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
-use rustc_target::spec::abi::Abi;
 
 use crate::traits;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -291,6 +290,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
+        // Keep this funtion in sync with extract_tupled_inputs_and_output_from_callable
+        // until the old solver (and thus this function) is removed.
+
         // Okay to skip binder because what we are inspecting doesn't involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
         match *self_ty.kind() {
@@ -299,31 +301,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 candidates.ambiguous = true; // Could wind up being a fn() type.
             }
             // Provide an impl, but only for suitable `fn` pointers.
-            ty::FnPtr(_) => {
-                if let ty::FnSig {
-                    unsafety: hir::Unsafety::Normal,
-                    abi: Abi::Rust,
-                    c_variadic: false,
-                    ..
-                } = self_ty.fn_sig(self.tcx()).skip_binder()
-                {
+            ty::FnPtr(sig) => {
+                if sig.is_fn_trait_compatible() {
                     candidates.vec.push(FnPointerCandidate { is_const: false });
                 }
             }
             // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
             ty::FnDef(def_id, _) => {
-                if let ty::FnSig {
-                    unsafety: hir::Unsafety::Normal,
-                    abi: Abi::Rust,
-                    c_variadic: false,
-                    ..
-                } = self_ty.fn_sig(self.tcx()).skip_binder()
+                if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
+                    && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
                 {
-                    if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
-                        candidates
-                            .vec
-                            .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
-                    }
+                    candidates
+                        .vec
+                        .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
                 }
             }
             _ => {}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 8e229dd8d6b..8546bbe52dc 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -22,7 +22,7 @@ use crate::traits::{
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{error_code, DelayDm, Diagnostic};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
 use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
@@ -350,6 +350,10 @@ fn report_conflicting_impls<'tcx>(
         impl_span: Span,
         err: &mut Diagnostic,
     ) {
+        if (overlap.trait_ref, overlap.self_ty).references_error() {
+            err.downgrade_to_delayed_bug();
+        }
+
         match tcx.span_of_impl(overlap.with_impl) {
             Ok(span) => {
                 err.span_label(span, "first implementation here");
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
index c6bb09b0417..492e21d9bdb 100644
--- a/library/std/src/sync/mpmc/array.rs
+++ b/library/std/src/sync/mpmc/array.rs
@@ -25,7 +25,8 @@ struct Slot<T> {
     /// The current stamp.
     stamp: AtomicUsize,
 
-    /// The message in this slot.
+    /// The message in this slot. Either read out in `read` or dropped through
+    /// `discard_all_messages`.
     msg: UnsafeCell<MaybeUninit<T>>,
 }
 
@@ -439,14 +440,13 @@ impl<T> Channel<T> {
         Some(self.cap)
     }
 
-    /// Disconnects the channel and wakes up all blocked senders and receivers.
+    /// Disconnects senders and wakes up all blocked receivers.
     ///
     /// Returns `true` if this call disconnected the channel.
-    pub(crate) fn disconnect(&self) -> bool {
+    pub(crate) fn disconnect_senders(&self) -> bool {
         let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
 
         if tail & self.mark_bit == 0 {
-            self.senders.disconnect();
             self.receivers.disconnect();
             true
         } else {
@@ -454,6 +454,85 @@ impl<T> Channel<T> {
         }
     }
 
+    /// Disconnects receivers and wakes up all blocked senders.
+    ///
+    /// Returns `true` if this call disconnected the channel.
+    ///
+    /// # Safety
+    /// May only be called once upon dropping the last receiver. The
+    /// destruction of all other receivers must have been observed with acquire
+    /// ordering or stronger.
+    pub(crate) unsafe fn disconnect_receivers(&self) -> bool {
+        let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
+        let disconnected = if tail & self.mark_bit == 0 {
+            self.senders.disconnect();
+            true
+        } else {
+            false
+        };
+
+        self.discard_all_messages(tail);
+        disconnected
+    }
+
+    /// Discards all messages.
+    ///
+    /// `tail` should be the current (and therefore last) value of `tail`.
+    ///
+    /// # Panicking
+    /// If a destructor panics, the remaining messages are leaked, matching the
+    /// behaviour of the unbounded channel.
+    ///
+    /// # Safety
+    /// This method must only be called when dropping the last receiver. The
+    /// destruction of all other receivers must have been observed with acquire
+    /// ordering or stronger.
+    unsafe fn discard_all_messages(&self, tail: usize) {
+        debug_assert!(self.is_disconnected());
+
+        // Only receivers modify `head`, so since we are the last one,
+        // this value will not change and will not be observed (since
+        // no new messages can be sent after disconnection).
+        let mut head = self.head.load(Ordering::Relaxed);
+        let tail = tail & !self.mark_bit;
+
+        let backoff = Backoff::new();
+        loop {
+            // Deconstruct the head.
+            let index = head & (self.mark_bit - 1);
+            let lap = head & !(self.one_lap - 1);
+
+            // Inspect the corresponding slot.
+            debug_assert!(index < self.buffer.len());
+            let slot = unsafe { self.buffer.get_unchecked(index) };
+            let stamp = slot.stamp.load(Ordering::Acquire);
+
+            // If the stamp is ahead of the head by 1, we may drop the message.
+            if head + 1 == stamp {
+                head = if index + 1 < self.cap {
+                    // Same lap, incremented index.
+                    // Set to `{ lap: lap, mark: 0, index: index + 1 }`.
+                    head + 1
+                } else {
+                    // One lap forward, index wraps around to zero.
+                    // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
+                    lap.wrapping_add(self.one_lap)
+                };
+
+                unsafe {
+                    (*slot.msg.get()).assume_init_drop();
+                }
+            // If the tail equals the head, that means the channel is empty.
+            } else if tail == head {
+                return;
+            // Otherwise, a sender is about to write into the slot, so we need
+            // to wait for it to update the stamp.
+            } else {
+                backoff.spin_heavy();
+            }
+        }
+    }
+
     /// Returns `true` if the channel is disconnected.
     pub(crate) fn is_disconnected(&self) -> bool {
         self.tail.load(Ordering::SeqCst) & self.mark_bit != 0
@@ -483,23 +562,3 @@ impl<T> Channel<T> {
         head.wrapping_add(self.one_lap) == tail & !self.mark_bit
     }
 }
-
-impl<T> Drop for Channel<T> {
-    fn drop(&mut self) {
-        // Get the index of the head.
-        let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1);
-
-        // Loop over all slots that hold a message and drop them.
-        for i in 0..self.len() {
-            // Compute the index of the next slot holding a message.
-            let index = if hix + i < self.cap { hix + i } else { hix + i - self.cap };
-
-            unsafe {
-                debug_assert!(index < self.buffer.len());
-                let slot = self.buffer.get_unchecked_mut(index);
-                let msg = &mut *slot.msg.get();
-                msg.as_mut_ptr().drop_in_place();
-            }
-        }
-    }
-}
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index 7a602cecd3b..2068dda393a 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -227,7 +227,7 @@ impl<T> Drop for Sender<T> {
     fn drop(&mut self) {
         unsafe {
             match &self.flavor {
-                SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()),
+                SenderFlavor::Array(chan) => chan.release(|c| c.disconnect_senders()),
                 SenderFlavor::List(chan) => chan.release(|c| c.disconnect_senders()),
                 SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()),
             }
@@ -403,7 +403,7 @@ impl<T> Drop for Receiver<T> {
     fn drop(&mut self) {
         unsafe {
             match &self.flavor {
-                ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()),
+                ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect_receivers()),
                 ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect_receivers()),
                 ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()),
             }
diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs
index 9d2f92ffc9b..632709fd98d 100644
--- a/library/std/src/sync/mpsc/sync_tests.rs
+++ b/library/std/src/sync/mpsc/sync_tests.rs
@@ -1,5 +1,6 @@
 use super::*;
 use crate::env;
+use crate::rc::Rc;
 use crate::sync::mpmc::SendTimeoutError;
 use crate::thread;
 use crate::time::Duration;
@@ -656,3 +657,15 @@ fn issue_15761() {
         repro()
     }
 }
+
+#[test]
+fn drop_unreceived() {
+    let (tx, rx) = sync_channel::<Rc<()>>(1);
+    let msg = Rc::new(());
+    let weak = Rc::downgrade(&msg);
+    assert!(tx.send(msg).is_ok());
+    drop(rx);
+    // Messages should be dropped immediately when the last receiver is destroyed.
+    assert!(weak.upgrade().is_none());
+    drop(tx);
+}
diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs
index 30356fa8519..43c0cdb657e 100644
--- a/library/std/src/sys/windows/args.rs
+++ b/library/std/src/sys/windows/args.rs
@@ -11,10 +11,11 @@ use crate::fmt;
 use crate::io;
 use crate::num::NonZeroU16;
 use crate::os::windows::prelude::*;
-use crate::path::PathBuf;
-use crate::sys::c;
+use crate::path::{Path, PathBuf};
+use crate::sys::path::get_long_path;
 use crate::sys::process::ensure_no_nuls;
 use crate::sys::windows::os::current_exe;
+use crate::sys::{c, to_u16s};
 use crate::sys_common::wstr::WStrUnits;
 use crate::vec;
 
@@ -311,7 +312,7 @@ pub(crate) fn make_bat_command_line(
 /// Takes a path and tries to return a non-verbatim path.
 ///
 /// This is necessary because cmd.exe does not support verbatim paths.
-pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
+pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> {
     use crate::ptr;
     use crate::sys::windows::fill_utf16_buf;
 
@@ -324,6 +325,8 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
     const N: u16 = b'N' as _;
     const C: u16 = b'C' as _;
 
+    let mut path = to_u16s(path)?;
+
     // Early return if the path is too long to remove the verbatim prefix.
     const LEGACY_MAX_PATH: usize = 260;
     if path.len() > LEGACY_MAX_PATH {
@@ -337,7 +340,13 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
             fill_utf16_buf(
                 |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
                 |full_path: &[u16]| {
-                    if full_path == &path[4..path.len() - 1] { full_path.into() } else { path }
+                    if full_path == &path[4..path.len() - 1] {
+                        let mut path: Vec<u16> = full_path.into();
+                        path.push(0);
+                        path
+                    } else {
+                        path
+                    }
                 },
             )
         },
@@ -350,7 +359,9 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
                 |buffer, size| c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()),
                 |full_path: &[u16]| {
                     if full_path == &path[6..path.len() - 1] {
-                        full_path.into()
+                        let mut path: Vec<u16> = full_path.into();
+                        path.push(0);
+                        path
                     } else {
                         // Restore the 'C' in "UNC".
                         path[6] = b'C' as u16;
@@ -360,6 +371,6 @@ pub(crate) fn to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
             )
         },
         // For everything else, leave the path unchanged.
-        _ => Ok(path),
+        _ => get_long_path(path, false),
     }
 }
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index beeca1917a9..c3573d14c7f 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -220,6 +220,19 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
 ///
 /// This path may or may not have a verbatim prefix.
 pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
+    let path = to_u16s(path)?;
+    get_long_path(path, true)
+}
+
+/// Get a normalized absolute path that can bypass path length limits.
+///
+/// Setting prefer_verbatim to true suggests a stronger preference for verbatim
+/// paths even when not strictly necessary. This allows the Windows API to avoid
+/// repeating our work. However, if the path may be given back to users or
+/// passed to other application then it's preferable to use non-verbatim paths
+/// when possible. Non-verbatim paths are better understood by users and handled
+/// by more software.
+pub(crate) fn get_long_path(mut path: Vec<u16>, prefer_verbatim: bool) -> io::Result<Vec<u16>> {
     // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
     // However, for APIs such as CreateDirectory[1], the limit is 248.
     //
@@ -243,7 +256,6 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
     // \\?\UNC\
     const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];
 
-    let mut path = to_u16s(path)?;
     if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) || path == &[0] {
         // Early return for paths that are already verbatim or empty.
         return Ok(path);
@@ -275,29 +287,34 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
         |mut absolute| {
             path.clear();
 
-            // Secondly, add the verbatim prefix. This is easier here because we know the
-            // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
-            let prefix = match absolute {
-                // C:\ => \\?\C:\
-                [_, COLON, SEP, ..] => VERBATIM_PREFIX,
-                // \\.\ => \\?\
-                [SEP, SEP, DOT, SEP, ..] => {
-                    absolute = &absolute[4..];
-                    VERBATIM_PREFIX
-                }
-                // Leave \\?\ and \??\ as-is.
-                [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
-                // \\ => \\?\UNC\
-                [SEP, SEP, ..] => {
-                    absolute = &absolute[2..];
-                    UNC_PREFIX
-                }
-                // Anything else we leave alone.
-                _ => &[],
-            };
-
-            path.reserve_exact(prefix.len() + absolute.len() + 1);
-            path.extend_from_slice(prefix);
+            // Only prepend the prefix if needed.
+            if prefer_verbatim || absolute.len() + 1 >= LEGACY_MAX_PATH {
+                // Secondly, add the verbatim prefix. This is easier here because we know the
+                // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
+                let prefix = match absolute {
+                    // C:\ => \\?\C:\
+                    [_, COLON, SEP, ..] => VERBATIM_PREFIX,
+                    // \\.\ => \\?\
+                    [SEP, SEP, DOT, SEP, ..] => {
+                        absolute = &absolute[4..];
+                        VERBATIM_PREFIX
+                    }
+                    // Leave \\?\ and \??\ as-is.
+                    [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
+                    // \\ => \\?\UNC\
+                    [SEP, SEP, ..] => {
+                        absolute = &absolute[2..];
+                        UNC_PREFIX
+                    }
+                    // Anything else we leave alone.
+                    _ => &[],
+                };
+
+                path.reserve_exact(prefix.len() + absolute.len() + 1);
+                path.extend_from_slice(prefix);
+            } else {
+                path.reserve_exact(absolute.len() + 1);
+            }
             path.extend_from_slice(absolute);
             path.push(0);
         },
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 10bc949e1f4..1c73b64e250 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -266,11 +266,7 @@ impl Command {
         let (program, mut cmd_str) = if is_batch_file {
             (
                 command_prompt()?,
-                args::make_bat_command_line(
-                    &args::to_user_path(program)?,
-                    &self.args,
-                    self.force_quotes_enabled,
-                )?,
+                args::make_bat_command_line(&program, &self.args, self.force_quotes_enabled)?,
             )
         } else {
             let cmd_str = make_command_line(&self.program, &self.args, self.force_quotes_enabled)?;
@@ -410,7 +406,7 @@ fn resolve_exe<'a>(
         if has_exe_suffix {
             // The application name is a path to a `.exe` file.
             // Let `CreateProcessW` figure out if it exists or not.
-            return path::maybe_verbatim(Path::new(exe_path));
+            return args::to_user_path(Path::new(exe_path));
         }
         let mut path = PathBuf::from(exe_path);
 
@@ -422,7 +418,7 @@ fn resolve_exe<'a>(
             // It's ok to use `set_extension` here because the intent is to
             // remove the extension that was just added.
             path.set_extension("");
-            return path::maybe_verbatim(&path);
+            return args::to_user_path(&path);
         }
     } else {
         ensure_no_nuls(exe_path)?;
@@ -510,7 +506,7 @@ where
 /// Check if a file exists without following symlinks.
 fn program_exists(path: &Path) -> Option<Vec<u16>> {
     unsafe {
-        let path = path::maybe_verbatim(path).ok()?;
+        let path = args::to_user_path(path).ok()?;
         // Getting attributes using `GetFileAttributesW` does not follow symlinks
         // and it will almost always be successful if the link exists.
         // There are some exceptions for special system files (e.g. the pagefile)
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.current.stderr
index 5cedf3ddb0f..319ed582e27 100644
--- a/tests/ui/async-await/in-trait/missing-send-bound.stderr
+++ b/tests/ui/async-await/in-trait/missing-send-bound.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/missing-send-bound.rs:3:12
+  --> $DIR/missing-send-bound.rs:5:12
    |
 LL | #![feature(async_fn_in_trait)]
    |            ^^^^^^^^^^^^^^^^^
@@ -8,19 +8,19 @@ LL | #![feature(async_fn_in_trait)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error: future cannot be sent between threads safely
-  --> $DIR/missing-send-bound.rs:15:20
+  --> $DIR/missing-send-bound.rs:17:20
    |
 LL |     assert_is_send(test::<T>());
    |                    ^^^^^^^^^^^ future returned by `test` is not `Send`
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
 note: future is not `Send` as it awaits another future which is not `Send`
-  --> $DIR/missing-send-bound.rs:11:5
+  --> $DIR/missing-send-bound.rs:13:5
    |
 LL |     T::bar().await;
    |     ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
 note: required by a bound in `assert_is_send`
-  --> $DIR/missing-send-bound.rs:19:27
+  --> $DIR/missing-send-bound.rs:21:27
    |
 LL | fn assert_is_send(_: impl Send) {}
    |                           ^^^^ required by this bound in `assert_is_send`
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.next.stderr b/tests/ui/async-await/in-trait/missing-send-bound.next.stderr
new file mode 100644
index 00000000000..319ed582e27
--- /dev/null
+++ b/tests/ui/async-await/in-trait/missing-send-bound.next.stderr
@@ -0,0 +1,29 @@
+warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/missing-send-bound.rs:5:12
+   |
+LL | #![feature(async_fn_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: future cannot be sent between threads safely
+  --> $DIR/missing-send-bound.rs:17:20
+   |
+LL |     assert_is_send(test::<T>());
+   |                    ^^^^^^^^^^^ future returned by `test` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
+note: future is not `Send` as it awaits another future which is not `Send`
+  --> $DIR/missing-send-bound.rs:13:5
+   |
+LL |     T::bar().await;
+   |     ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
+note: required by a bound in `assert_is_send`
+  --> $DIR/missing-send-bound.rs:21:27
+   |
+LL | fn assert_is_send(_: impl Send) {}
+   |                           ^^^^ required by this bound in `assert_is_send`
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs
index 78922b59b27..705fcf322f9 100644
--- a/tests/ui/async-await/in-trait/missing-send-bound.rs
+++ b/tests/ui/async-await/in-trait/missing-send-bound.rs
@@ -1,4 +1,6 @@
 // edition:2021
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 //~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs
new file mode 100644
index 00000000000..e13dfbacd24
--- /dev/null
+++ b/tests/ui/const-generics/bad-subst-const-kind.rs
@@ -0,0 +1,13 @@
+// incremental
+#![crate_type = "lib"]
+
+trait Q {
+    const ASSOC: usize;
+}
+
+impl<const N: u64> Q for [u8; N] {
+    //~^ ERROR mismatched types
+    const ASSOC: usize = 1;
+}
+
+pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr
new file mode 100644
index 00000000000..bd24f9140e4
--- /dev/null
+++ b/tests/ui/const-generics/bad-subst-const-kind.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/bad-subst-const-kind.rs:8:31
+   |
+LL | impl<const N: u64> Q for [u8; N] {
+   |                               ^ expected `usize`, found `u64`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/macros/nested-use-as.rs b/tests/ui/macros/nested-use-as.rs
new file mode 100644
index 00000000000..21aa81e8092
--- /dev/null
+++ b/tests/ui/macros/nested-use-as.rs
@@ -0,0 +1,83 @@
+// check-pass
+// edition:2018
+// issue: https://github.com/rust-lang/rust/issues/97534
+
+macro_rules! m {
+    () => {
+        macro_rules! foo {
+            () => {}
+        }
+        use foo as bar;
+    }
+}
+
+m!{}
+
+use bar as baz;
+
+baz!{}
+
+macro_rules! foo2 {
+    () => {};
+}
+
+macro_rules! m2 {
+    () => {
+        use foo2 as bar2;
+    };
+}
+
+m2! {}
+
+use bar2 as baz2;
+
+baz2! {}
+
+macro_rules! n1 {
+    () => {
+        macro_rules! n2 {
+            () => {
+                macro_rules! n3 {
+                    () => {
+                        macro_rules! n4 {
+                            () => {}
+                        }
+                        use n4 as c4;
+                    }
+                }
+                use n3 as c3;
+            }
+        }
+        use n2 as c2;
+    }
+}
+
+use n1 as c1;
+c1!{}
+use c2 as a2;
+a2!{}
+use c3 as a3;
+a3!{}
+use c4 as a4;
+a4!{}
+
+// https://github.com/rust-lang/rust/pull/108729#issuecomment-1474750675
+// reversed
+use d5 as d6;
+use d4 as d5;
+use d3 as d4;
+use d2 as d3;
+use d1 as d2;
+use foo2 as d1;
+d6! {}
+
+// mess
+use f3 as f4;
+f5! {}
+use f1 as f2;
+use f4 as f5;
+use f2 as f3;
+use foo2 as f1;
+
+fn main() {
+}
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
index 582b480aa25..5fd7c647c25 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
@@ -2,11 +2,11 @@
 
 // An impl that has an erroneous const substitution should not specialize one
 // that is well-formed.
-
+#[derive(Clone)]
 struct S<const L: usize>;
 
 impl<const N: i32> Copy for S<N> {}
+//~^ ERROR the constant `N` is not of type `usize`
 impl<const M: usize> Copy for S<M> {}
-//~^ ERROR conflicting implementations of trait `Copy` for type `S<_>`
 
 fn main() {}
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
index a3906a9a22f..6d7028c5e70 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
@@ -1,11 +1,14 @@
-error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
-  --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1
+error: the constant `N` is not of type `usize`
+  --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
    |
 LL | impl<const N: i32> Copy for S<N> {}
-   | -------------------------------- first implementation here
-LL | impl<const M: usize> Copy for S<M> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
+   |                             ^^^^
+   |
+note: required by a bound in `S`
+  --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10
+   |
+LL | struct S<const L: usize>;
+   |          ^^^^^^^^^^^^^^ required by this bound in `S`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/suggestions/issue-109396.rs b/tests/ui/suggestions/issue-109396.rs
new file mode 100644
index 00000000000..b6c464d45a2
--- /dev/null
+++ b/tests/ui/suggestions/issue-109396.rs
@@ -0,0 +1,12 @@
+fn main() {
+    {
+        let mut mutex = std::mem::zeroed(
+            //~^ ERROR this function takes 0 arguments but 4 arguments were supplied
+            file.as_raw_fd(),
+            //~^ ERROR expected value, found macro `file`
+            0,
+            0,
+            0,
+        );
+    }
+}
diff --git a/tests/ui/suggestions/issue-109396.stderr b/tests/ui/suggestions/issue-109396.stderr
new file mode 100644
index 00000000000..eca160e2fab
--- /dev/null
+++ b/tests/ui/suggestions/issue-109396.stderr
@@ -0,0 +1,34 @@
+error[E0423]: expected value, found macro `file`
+  --> $DIR/issue-109396.rs:5:13
+   |
+LL |             file.as_raw_fd(),
+   |             ^^^^ not a value
+
+error[E0061]: this function takes 0 arguments but 4 arguments were supplied
+  --> $DIR/issue-109396.rs:3:25
+   |
+LL |         let mut mutex = std::mem::zeroed(
+   |                         ^^^^^^^^^^^^^^^^
+LL |
+LL |             file.as_raw_fd(),
+   |             ---------------- unexpected argument
+LL |
+LL |             0,
+   |             - unexpected argument of type `{integer}`
+LL |             0,
+   |             - unexpected argument of type `{integer}`
+LL |             0,
+   |             - unexpected argument of type `{integer}`
+   |
+note: function defined here
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+help: remove the extra arguments
+   |
+LL -             file.as_raw_fd(),
+LL +             ,
+   |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0061, E0423.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs
index d566ead105c..0599e51d7ad 100644
--- a/tests/ui/traits/new-solver/fn-trait.rs
+++ b/tests/ui/traits/new-solver/fn-trait.rs
@@ -1,5 +1,4 @@
 // compile-flags: -Ztrait-solver=next
-// check-pass
 
 fn require_fn(_: impl Fn() -> i32) {}
 
@@ -7,7 +6,27 @@ fn f() -> i32 {
     1i32
 }
 
+extern "C" fn g() -> i32 {
+    2i32
+}
+
+unsafe fn h() -> i32 {
+    2i32
+}
+
 fn main() {
     require_fn(f);
     require_fn(f as fn() -> i32);
+    require_fn(f as unsafe fn() -> i32);
+    //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
+    //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
+    require_fn(g);
+    //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
+    //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32`
+    require_fn(g as extern "C" fn() -> i32);
+    //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
+    //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
+    require_fn(h);
+    //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}`
+    //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32`
 }
diff --git a/tests/ui/traits/new-solver/fn-trait.stderr b/tests/ui/traits/new-solver/fn-trait.stderr
new file mode 100644
index 00000000000..d52bcaf25b8
--- /dev/null
+++ b/tests/ui/traits/new-solver/fn-trait.stderr
@@ -0,0 +1,124 @@
+error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
+  --> $DIR/fn-trait.rs:20:16
+   |
+LL |     require_fn(f as unsafe fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32`
+   = note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:20:16
+   |
+LL |     require_fn(f as unsafe fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
+  --> $DIR/fn-trait.rs:23:16
+   |
+LL |     require_fn(g);
+   |     ---------- ^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() -> i32 {g}`
+   = note: wrap the `extern "C" fn() -> i32 {g}` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:23:16
+   |
+LL |     require_fn(g);
+   |     ---------- ^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
+  --> $DIR/fn-trait.rs:26:16
+   |
+LL |     require_fn(g as extern "C" fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for `extern "C" fn() -> i32`
+   = note: wrap the `extern "C" fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:26:16
+   |
+LL |     require_fn(g as extern "C" fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}`
+  --> $DIR/fn-trait.rs:29:16
+   |
+LL |     require_fn(h);
+   |     ---------- ^ call the function in a closure: `|| unsafe { /* code */ }`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}`
+   = note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:29:16
+   |
+LL |     require_fn(h);
+   |     ---------- ^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.