about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs37
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs3
-rw-r--r--library/alloc/src/boxed.rs31
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/core/src/const_closure.rs30
-rw-r--r--library/core/src/intrinsics.rs66
-rw-r--r--library/core/src/ops/function.rs324
-rw-r--r--src/test/codegen/avr/avr-func-addrspace.rs16
-rw-r--r--src/test/incremental/hashes/extern_mods.rs4
-rw-r--r--src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs3
-rw-r--r--src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs3
-rw-r--r--src/test/ui/abi/issues/issue-22565-rust-call.rs13
-rw-r--r--src/test/ui/abi/issues/issue-22565-rust-call.stderr33
-rw-r--r--src/test/ui/abi/rustcall-generic.rs4
-rw-r--r--src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs6
-rw-r--r--src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr24
-rw-r--r--src/test/ui/borrowck/borrowck-move-by-capture.rs6
-rw-r--r--src/test/ui/c-variadic/issue-86053-1.stderr4
-rw-r--r--src/test/ui/cannot-mutate-captured-non-mut-var.rs4
-rw-r--r--src/test/ui/chalkify/closure.rs5
-rw-r--r--src/test/ui/chalkify/closure.stderr88
-rw-r--r--src/test/ui/chalkify/trait-objects.rs3
-rw-r--r--src/test/ui/chalkify/trait-objects.stderr28
-rw-r--r--src/test/ui/closures/issue-78720.stderr4
-rw-r--r--src/test/ui/error-codes/E0059.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.rs3
-rw-r--r--src/test/ui/feature-gates/feature-gate-abi.stderr68
-rw-r--r--src/test/ui/function-pointer/unsized-ret.rs3
-rw-r--r--src/test/ui/function-pointer/unsized-ret.stderr12
-rw-r--r--src/test/ui/issues/issue-12127.rs4
-rw-r--r--src/test/ui/issues/issue-23024.stderr2
-rw-r--r--src/test/ui/issues/issue-7607-1.stderr4
-rw-r--r--src/test/ui/lang-items/lang-item-missing-generator.rs6
-rw-r--r--src/test/ui/lang-items/lang-item-missing-generator.stderr11
-rw-r--r--src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs4
-rw-r--r--src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs4
-rw-r--r--src/test/ui/overloaded/overloaded-calls-nontuple.rs17
-rw-r--r--src/test/ui/overloaded/overloaded-calls-nontuple.stderr47
-rw-r--r--src/test/ui/parser/kw-in-trait-bounds.stderr16
-rw-r--r--src/test/ui/span/issue-11925.rs4
-rw-r--r--src/test/ui/typeck/issue-83693.stderr4
-rw-r--r--src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs2
-rw-r--r--src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr20
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-illegal-move.rs8
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs6
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs4
53 files changed, 841 insertions, 242 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 0117bdd0ba8..416b555db5c 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -21,6 +21,7 @@ use rustc_middle::ty::{GenericArgKind, InternalSubsts};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::autoderef::Autoderef;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
@@ -1542,6 +1543,33 @@ fn check_fn_or_method<'tcx>(
         sig.output(),
         hir_decl.output.span(),
     );
+
+    if sig.abi == Abi::RustCall {
+        let span = tcx.def_span(def_id);
+        let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
+        let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 });
+        // Check that the argument is a tuple
+        if let Some(ty) = inputs.next() {
+            wfcx.register_bound(
+                ObligationCause::new(span, wfcx.body_id, ObligationCauseCode::RustCall),
+                wfcx.param_env,
+                *ty,
+                tcx.require_lang_item(hir::LangItem::Tuple, Some(span)),
+            );
+        } else {
+            tcx.sess.span_err(
+                hir_decl.inputs.last().map_or(span, |input| input.span),
+                "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+            );
+        }
+        // No more inputs other than the `self` type and the tuple type
+        if inputs.next().is_some() {
+            tcx.sess.span_err(
+                hir_decl.inputs.last().map_or(span, |input| input.span),
+                "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+            );
+        }
+    }
 }
 
 /// Basically `check_associated_type_bounds`, but separated for now and should be
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 000f4c9b684..2b019c8c9b7 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -468,6 +468,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             def_id,
         );
 
+        if fn_sig.abi == abi::Abi::RustCall {
+            let sp = arg_exprs.last().map_or(call_expr.span, |expr| expr.span);
+            if let Some(ty) = fn_sig.inputs().last().copied() {
+                self.register_bound(
+                    ty,
+                    self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
+                    traits::ObligationCause::new(sp, self.body_id, traits::RustCall),
+                );
+            } else {
+                self.tcx.sess.span_err(
+                        sp,
+                        "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+                    );
+            }
+        }
+
         fn_sig.output()
     }
 
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 80147d90091..37af6e79c3e 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -6,13 +6,11 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
 use rustc_hir_analysis::check::fn_maybe_err;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::RegionVariableOrigin;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
-use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use std::cell::RefCell;
 
@@ -56,41 +54,6 @@ pub(super) fn check_fn<'a, 'tcx>(
 
     fn_maybe_err(tcx, span, fn_sig.abi);
 
-    if fn_sig.abi == Abi::RustCall {
-        let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
-
-        let err = || {
-            let item = match tcx.hir().get(fn_id) {
-                Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
-                Node::ImplItem(hir::ImplItem {
-                    kind: hir::ImplItemKind::Fn(header, ..), ..
-                }) => Some(header),
-                Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(header, ..),
-                    ..
-                }) => Some(header),
-                // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
-                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
-                node => bug!("Item being checked wasn't a function/closure: {:?}", node),
-            };
-
-            if let Some(header) = item {
-                tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
-            }
-        };
-
-        if fn_sig.inputs().len() != expected_args {
-            err()
-        } else {
-            // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
-            //   This will probably require wide-scale changes to support a TupleKind obligation
-            //   We can't resolve this without knowing the type of the param
-            if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
-                err()
-            }
-        }
-    }
-
     if body.generator_kind.is_some() && can_be_generator.is_some() {
         let yield_ty = fcx
             .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index e1955d838f2..4066cca8a4b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -136,6 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             tuple_arguments,
             Some(method.def_id),
         );
+
         method.sig.output()
     }
 
@@ -214,7 +215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         "cannot use call notation; the first type parameter \
                          for the function trait is neither a tuple nor unit"
                     )
-                    .emit();
+                    .delay_as_bug();
                     (self.err_args(provided_args.len()), None)
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index d1762598a52..624443d9594 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -458,7 +458,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'
 /// # fn f(x: (isize, isize)) {}
 /// f((1, 2));
 /// ```
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq)]
 enum TupleArgumentsFlag {
     DontTupleArguments,
     TupleArguments,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 07ee758b32c..a29f0722ff7 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -438,6 +438,8 @@ pub enum ObligationCauseCode<'tcx> {
     },
 
     AscribeUserTypeProvePredicate(Span),
+
+    RustCall,
 }
 
 /// The 'location' at which we try to perform HIR-based wf checking.
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index dacce5cd2f6..54281f91205 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -700,6 +700,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             }
                         }
 
+                        if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
+                            match obligation.cause.code().peel_derives() {
+                                ObligationCauseCode::RustCall => {
+                                    err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
+                                }
+                                ObligationCauseCode::BindingObligation(def_id, _)
+                                | ObligationCauseCode::ItemObligation(def_id)
+                                    if ty::ClosureKind::from_def_id(tcx, *def_id).is_some() =>
+                                {
+                                    err.code(rustc_errors::error_code!(E0059));
+                                    err.set_primary_message(format!(
+                                        "type parameter to bare `{}` trait must be a tuple",
+                                        tcx.def_path_str(*def_id)
+                                    ));
+                                }
+                                _ => {}
+                            }
+                        }
+
                         if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
                             && predicate_is_const
                         {
@@ -848,12 +867,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             );
                         }
 
-                        let is_fn_trait = [
-                            self.tcx.lang_items().fn_trait(),
-                            self.tcx.lang_items().fn_mut_trait(),
-                            self.tcx.lang_items().fn_once_trait(),
-                        ]
-                        .contains(&Some(trait_ref.def_id()));
+                        let is_fn_trait =
+                            ty::ClosureKind::from_def_id(tcx, trait_ref.def_id()).is_some();
                         let is_target_feature_fn = if let ty::FnDef(def_id, _) =
                             *trait_ref.skip_binder().self_ty().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 d7606d88803..0f4aa87b43f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2407,7 +2407,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             | ObligationCauseCode::CheckAssociatedTypeBounds { .. }
             | ObligationCauseCode::LetElse
             | ObligationCauseCode::BinOp { .. }
-            | ObligationCauseCode::AscribeUserTypeProvePredicate(..) => {}
+            | ObligationCauseCode::AscribeUserTypeProvePredicate(..)
+            | ObligationCauseCode::RustCall => {}
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index b7e7d5a38a5..66f4c19e0f9 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -158,6 +158,8 @@ use core::hash::{Hash, Hasher};
 #[cfg(not(no_global_oom_handling))]
 use core::iter::FromIterator;
 use core::iter::{FusedIterator, Iterator};
+#[cfg(not(bootstrap))]
+use core::marker::Tuple;
 use core::marker::{Destruct, Unpin, Unsize};
 use core::mem;
 use core::ops::{
@@ -1979,6 +1981,7 @@ impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A
 #[stable(feature = "fused", since = "1.26.0")]
 impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
 
+#[cfg(bootstrap)]
 #[stable(feature = "boxed_closure_impls", since = "1.35.0")]
 impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
     type Output = <F as FnOnce<Args>>::Output;
@@ -1988,6 +1991,17 @@ impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
     }
 }
 
+#[cfg(not(bootstrap))]
+#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
+impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
+    type Output = <F as FnOnce<Args>>::Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
+        <F as FnOnce<Args>>::call_once(*self, args)
+    }
+}
+
+#[cfg(bootstrap)]
 #[stable(feature = "boxed_closure_impls", since = "1.35.0")]
 impl<Args, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
@@ -1995,6 +2009,15 @@ impl<Args, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
     }
 }
 
+#[cfg(not(bootstrap))]
+#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
+impl<Args: Tuple, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
+        <F as FnMut<Args>>::call_mut(self, args)
+    }
+}
+
+#[cfg(bootstrap)]
 #[stable(feature = "boxed_closure_impls", since = "1.35.0")]
 impl<Args, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
     extern "rust-call" fn call(&self, args: Args) -> Self::Output {
@@ -2002,6 +2025,14 @@ impl<Args, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
     }
 }
 
+#[cfg(not(bootstrap))]
+#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
+impl<Args: Tuple, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
+    extern "rust-call" fn call(&self, args: Args) -> Self::Output {
+        <F as Fn<Args>>::call(self, args)
+    }
+}
+
 #[unstable(feature = "coerce_unsized", issue = "27732")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
 
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index ce36b116f13..008926666c1 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -150,6 +150,7 @@
 #![feature(trusted_len)]
 #![feature(trusted_random_access)]
 #![feature(try_trait_v2)]
+#![cfg_attr(not(bootstrap), feature(tuple_trait))]
 #![feature(unchecked_math)]
 #![feature(unicode_internals)]
 #![feature(unsize)]
diff --git a/library/core/src/const_closure.rs b/library/core/src/const_closure.rs
index 9e9c02093be..151c8e6d898 100644
--- a/library/core/src/const_closure.rs
+++ b/library/core/src/const_closure.rs
@@ -1,4 +1,6 @@
 use crate::marker::Destruct;
+#[cfg(not(bootstrap))]
+use crate::marker::Tuple;
 
 /// Struct representing a closure with mutably borrowed data.
 ///
@@ -44,6 +46,7 @@ impl<'a, CapturedData: ?Sized, Function> ConstFnMutClosure<&'a mut CapturedData,
 
 macro_rules! impl_fn_mut_tuple {
     ($($var:ident)*) => {
+        #[cfg(bootstrap)]
         #[allow(unused_parens)]
         impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
             FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
@@ -56,6 +59,7 @@ macro_rules! impl_fn_mut_tuple {
             self.call_mut(args)
             }
         }
+        #[cfg(bootstrap)]
         #[allow(unused_parens)]
         impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
             FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
@@ -68,6 +72,32 @@ macro_rules! impl_fn_mut_tuple {
                 (self.func)(($($var),*), args)
             }
         }
+        #[cfg(not(bootstrap))]
+        #[allow(unused_parens)]
+        impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
+            FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
+        where
+            Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue+ ~const Destruct,
+        {
+            type Output = ClosureReturnValue;
+
+            extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
+            self.call_mut(args)
+            }
+        }
+        #[cfg(not(bootstrap))]
+        #[allow(unused_parens)]
+        impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
+            FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
+        where
+            Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
+        {
+            extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
+                #[allow(non_snake_case)]
+                let ($($var),*) = &mut self.data;
+                (self.func)(($($var),*), args)
+            }
+        }
     };
 }
 impl_fn_mut_tuple!(A);
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 1dc79afe83f..bfbd4301230 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -55,6 +55,8 @@
 #![allow(missing_docs)]
 
 use crate::marker::DiscriminantKind;
+#[cfg(not(bootstrap))]
+use crate::marker::Tuple;
 use crate::mem;
 
 // These imports are used for simplifying intra-doc links
@@ -2169,11 +2171,75 @@ extern "rust-intrinsic" {
     /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
     /// which violates the principle that a `const fn` must behave the same at
     /// compile-time and at run-time. The unsafe code in crate B is fine.
+    #[cfg(bootstrap)]
     #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
     pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
     where
         G: FnOnce<ARG, Output = RET>,
         F: FnOnce<ARG, Output = RET>;
+
+    /// Selects which function to call depending on the context.
+    ///
+    /// If this function is evaluated at compile-time, then a call to this
+    /// intrinsic will be replaced with a call to `called_in_const`. It gets
+    /// replaced with a call to `called_at_rt` otherwise.
+    ///
+    /// # Type Requirements
+    ///
+    /// The two functions must be both function items. They cannot be function
+    /// pointers or closures. The first function must be a `const fn`.
+    ///
+    /// `arg` will be the tupled arguments that will be passed to either one of
+    /// the two functions, therefore, both functions must accept the same type of
+    /// arguments. Both functions must return RET.
+    ///
+    /// # Safety
+    ///
+    /// The two functions must behave observably equivalent. Safe code in other
+    /// crates may assume that calling a `const fn` at compile-time and at run-time
+    /// produces the same result. A function that produces a different result when
+    /// evaluated at run-time, or has any other observable side-effects, is
+    /// *unsound*.
+    ///
+    /// Here is an example of how this could cause a problem:
+    /// ```no_run
+    /// #![feature(const_eval_select)]
+    /// #![feature(core_intrinsics)]
+    /// use std::hint::unreachable_unchecked;
+    /// use std::intrinsics::const_eval_select;
+    ///
+    /// // Crate A
+    /// pub const fn inconsistent() -> i32 {
+    ///     fn runtime() -> i32 { 1 }
+    ///     const fn compiletime() -> i32 { 2 }
+    ///
+    ///     unsafe {
+    //          // ⚠ This code violates the required equivalence of `compiletime`
+    ///         // and `runtime`.
+    ///         const_eval_select((), compiletime, runtime)
+    ///     }
+    /// }
+    ///
+    /// // Crate B
+    /// const X: i32 = inconsistent();
+    /// let x = inconsistent();
+    /// if x != X { unsafe { unreachable_unchecked(); }}
+    /// ```
+    ///
+    /// This code causes Undefined Behavior when being run, since the
+    /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
+    /// which violates the principle that a `const fn` must behave the same at
+    /// compile-time and at run-time. The unsafe code in crate B is fine.
+    #[cfg(not(bootstrap))]
+    #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
+    pub fn const_eval_select<ARG: Tuple, F, G, RET>(
+        arg: ARG,
+        called_in_const: F,
+        called_at_rt: G,
+    ) -> RET
+    where
+        G: FnOnce<ARG, Output = RET>,
+        F: FnOnce<ARG, Output = RET>;
 }
 
 // Some functions are defined here because they accidentally got made
diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs
index 2e0a752c815..8d4b0a7ccac 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -1,3 +1,6 @@
+#[cfg(not(bootstrap))]
+use crate::marker::Tuple;
+
 /// The version of the call operator that takes an immutable receiver.
 ///
 /// Instances of `Fn` can be called repeatedly without mutating state.
@@ -51,6 +54,7 @@
 /// let double = |x| x * 2;
 /// assert_eq!(call_with_one(double), 2);
 /// ```
+#[cfg(bootstrap)]
 #[lang = "fn"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Fn"]
@@ -71,13 +75,93 @@
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[cfg_attr(not(bootstrap), const_trait)]
 pub trait Fn<Args>: FnMut<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
 }
 
+/// The version of the call operator that takes an immutable receiver.
+///
+/// Instances of `Fn` can be called repeatedly without mutating state.
+///
+/// *This trait (`Fn`) is not to be confused with [function pointers]
+/// (`fn`).*
+///
+/// `Fn` is implemented automatically by closures which only take immutable
+/// references to captured variables or don't capture anything at all, as well
+/// as (safe) [function pointers] (with some caveats, see their documentation
+/// for more details). Additionally, for any type `F` that implements `Fn`, `&F`
+/// implements `Fn`, too.
+///
+/// Since both [`FnMut`] and [`FnOnce`] are supertraits of `Fn`, any
+/// instance of `Fn` can be used as a parameter where a [`FnMut`] or [`FnOnce`]
+/// is expected.
+///
+/// Use `Fn` as a bound when you want to accept a parameter of function-like
+/// type and need to call it repeatedly and without mutating state (e.g., when
+/// calling it concurrently). If you do not need such strict requirements, use
+/// [`FnMut`] or [`FnOnce`] as bounds.
+///
+/// See the [chapter on closures in *The Rust Programming Language*][book] for
+/// some more information on this topic.
+///
+/// Also of note is the special syntax for `Fn` traits (e.g.
+/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
+/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
+///
+/// [book]: ../../book/ch13-01-closures.html
+/// [function pointers]: fn
+/// [nomicon]: ../../nomicon/hrtb.html
+///
+/// # Examples
+///
+/// ## Calling a closure
+///
+/// ```
+/// let square = |x| x * x;
+/// assert_eq!(square(5), 25);
+/// ```
+///
+/// ## Using a `Fn` parameter
+///
+/// ```
+/// fn call_with_one<F>(func: F) -> usize
+///     where F: Fn(usize) -> usize {
+///     func(1)
+/// }
+///
+/// let double = |x| x * 2;
+/// assert_eq!(call_with_one(double), 2);
+/// ```
+#[cfg(not(bootstrap))]
+#[lang = "fn"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "Fn"]
+#[rustc_paren_sugar]
+#[rustc_on_unimplemented(
+    on(
+        Args = "()",
+        note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
+    ),
+    on(
+        _Self = "unsafe fn",
+        note = "unsafe function cannot be called generically without an unsafe block",
+        // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
+        label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
+    ),
+    message = "expected a `{Fn}<{Args}>` closure, found `{Self}`",
+    label = "expected an `Fn<{Args}>` closure, found `{Self}`"
+)]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
+pub trait Fn<Args: Tuple>: FnMut<Args> {
+    /// Performs the call operation.
+    #[unstable(feature = "fn_traits", issue = "29625")]
+    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
 /// The version of the call operator that takes a mutable receiver.
 ///
 /// Instances of `FnMut` can be called repeatedly and may mutate state.
@@ -139,6 +223,7 @@ pub trait Fn<Args>: FnMut<Args> {
 ///
 /// assert_eq!(x, 5);
 /// ```
+#[cfg(bootstrap)]
 #[lang = "fn_mut"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "FnMut"]
@@ -159,13 +244,101 @@ pub trait Fn<Args>: FnMut<Args> {
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[cfg_attr(not(bootstrap), const_trait)]
 pub trait FnMut<Args>: FnOnce<Args> {
     /// Performs the call operation.
     #[unstable(feature = "fn_traits", issue = "29625")]
     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
 }
 
+/// The version of the call operator that takes a mutable receiver.
+///
+/// Instances of `FnMut` can be called repeatedly and may mutate state.
+///
+/// `FnMut` is implemented automatically by closures which take mutable
+/// references to captured variables, as well as all types that implement
+/// [`Fn`], e.g., (safe) [function pointers] (since `FnMut` is a supertrait of
+/// [`Fn`]). Additionally, for any type `F` that implements `FnMut`, `&mut F`
+/// implements `FnMut`, too.
+///
+/// Since [`FnOnce`] is a supertrait of `FnMut`, any instance of `FnMut` can be
+/// used where a [`FnOnce`] is expected, and since [`Fn`] is a subtrait of
+/// `FnMut`, any instance of [`Fn`] can be used where `FnMut` is expected.
+///
+/// Use `FnMut` as a bound when you want to accept a parameter of function-like
+/// type and need to call it repeatedly, while allowing it to mutate state.
+/// If you don't want the parameter to mutate state, use [`Fn`] as a
+/// bound; if you don't need to call it repeatedly, use [`FnOnce`].
+///
+/// See the [chapter on closures in *The Rust Programming Language*][book] for
+/// some more information on this topic.
+///
+/// Also of note is the special syntax for `Fn` traits (e.g.
+/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
+/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
+///
+/// [book]: ../../book/ch13-01-closures.html
+/// [function pointers]: fn
+/// [nomicon]: ../../nomicon/hrtb.html
+///
+/// # Examples
+///
+/// ## Calling a mutably capturing closure
+///
+/// ```
+/// let mut x = 5;
+/// {
+///     let mut square_x = || x *= x;
+///     square_x();
+/// }
+/// assert_eq!(x, 25);
+/// ```
+///
+/// ## Using a `FnMut` parameter
+///
+/// ```
+/// fn do_twice<F>(mut func: F)
+///     where F: FnMut()
+/// {
+///     func();
+///     func();
+/// }
+///
+/// let mut x: usize = 1;
+/// {
+///     let add_two_to_x = || x += 2;
+///     do_twice(add_two_to_x);
+/// }
+///
+/// assert_eq!(x, 5);
+/// ```
+#[cfg(not(bootstrap))]
+#[lang = "fn_mut"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "FnMut"]
+#[rustc_paren_sugar]
+#[rustc_on_unimplemented(
+    on(
+        Args = "()",
+        note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
+    ),
+    on(
+        _Self = "unsafe fn",
+        note = "unsafe function cannot be called generically without an unsafe block",
+        // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
+        label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
+    ),
+    message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`",
+    label = "expected an `FnMut<{Args}>` closure, found `{Self}`"
+)]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
+pub trait FnMut<Args: Tuple>: FnOnce<Args> {
+    /// Performs the call operation.
+    #[unstable(feature = "fn_traits", issue = "29625")]
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
 /// The version of the call operator that takes a by-value receiver.
 ///
 /// Instances of `FnOnce` can be called, but might not be callable multiple
@@ -219,6 +392,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
 ///
 /// // `consume_and_return_x` can no longer be invoked at this point
 /// ```
+#[cfg(bootstrap)]
 #[lang = "fn_once"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "FnOnce"]
@@ -239,7 +413,6 @@ pub trait FnMut<Args>: FnOnce<Args> {
 )]
 #[fundamental] // so that regex can rely that `&str: !FnMut`
 #[must_use = "closures are lazy and do nothing unless called"]
-#[cfg_attr(not(bootstrap), const_trait)]
 pub trait FnOnce<Args> {
     /// The returned type after the call operator is used.
     #[lang = "fn_once_output"]
@@ -251,6 +424,93 @@ pub trait FnOnce<Args> {
     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
 }
 
+/// The version of the call operator that takes a by-value receiver.
+///
+/// Instances of `FnOnce` can be called, but might not be callable multiple
+/// times. Because of this, if the only thing known about a type is that it
+/// implements `FnOnce`, it can only be called once.
+///
+/// `FnOnce` is implemented automatically by closures that might consume captured
+/// variables, as well as all types that implement [`FnMut`], e.g., (safe)
+/// [function pointers] (since `FnOnce` is a supertrait of [`FnMut`]).
+///
+/// Since both [`Fn`] and [`FnMut`] are subtraits of `FnOnce`, any instance of
+/// [`Fn`] or [`FnMut`] can be used where a `FnOnce` is expected.
+///
+/// Use `FnOnce` as a bound when you want to accept a parameter of function-like
+/// type and only need to call it once. If you need to call the parameter
+/// repeatedly, use [`FnMut`] as a bound; if you also need it to not mutate
+/// state, use [`Fn`].
+///
+/// See the [chapter on closures in *The Rust Programming Language*][book] for
+/// some more information on this topic.
+///
+/// Also of note is the special syntax for `Fn` traits (e.g.
+/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
+/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
+///
+/// [book]: ../../book/ch13-01-closures.html
+/// [function pointers]: fn
+/// [nomicon]: ../../nomicon/hrtb.html
+///
+/// # Examples
+///
+/// ## Using a `FnOnce` parameter
+///
+/// ```
+/// fn consume_with_relish<F>(func: F)
+///     where F: FnOnce() -> String
+/// {
+///     // `func` consumes its captured variables, so it cannot be run more
+///     // than once.
+///     println!("Consumed: {}", func());
+///
+///     println!("Delicious!");
+///
+///     // Attempting to invoke `func()` again will throw a `use of moved
+///     // value` error for `func`.
+/// }
+///
+/// let x = String::from("x");
+/// let consume_and_return_x = move || x;
+/// consume_with_relish(consume_and_return_x);
+///
+/// // `consume_and_return_x` can no longer be invoked at this point
+/// ```
+#[cfg(not(bootstrap))]
+#[lang = "fn_once"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "FnOnce"]
+#[rustc_paren_sugar]
+#[rustc_on_unimplemented(
+    on(
+        Args = "()",
+        note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
+    ),
+    on(
+        _Self = "unsafe fn",
+        note = "unsafe function cannot be called generically without an unsafe block",
+        // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
+        label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
+    ),
+    message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`",
+    label = "expected an `FnOnce<{Args}>` closure, found `{Self}`"
+)]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
+pub trait FnOnce<Args: Tuple> {
+    /// The returned type after the call operator is used.
+    #[lang = "fn_once_output"]
+    #[stable(feature = "fn_once_output", since = "1.12.0")]
+    type Output;
+
+    /// Performs the call operation.
+    #[unstable(feature = "fn_traits", issue = "29625")]
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[cfg(bootstrap)]
 mod impls {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
@@ -310,3 +570,61 @@ mod impls {
         }
     }
 }
+
+#[cfg(not(bootstrap))]
+mod impls {
+    use crate::marker::Tuple;
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    impl<A: Tuple, F: ?Sized> Fn<A> for &F
+    where
+        F: Fn<A>,
+    {
+        extern "rust-call" fn call(&self, args: A) -> F::Output {
+            (**self).call(args)
+        }
+    }
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    impl<A: Tuple, F: ?Sized> FnMut<A> for &F
+    where
+        F: Fn<A>,
+    {
+        extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
+            (**self).call(args)
+        }
+    }
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    impl<A: Tuple, F: ?Sized> FnOnce<A> for &F
+    where
+        F: Fn<A>,
+    {
+        type Output = F::Output;
+
+        extern "rust-call" fn call_once(self, args: A) -> F::Output {
+            (*self).call(args)
+        }
+    }
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    impl<A: Tuple, F: ?Sized> FnMut<A> for &mut F
+    where
+        F: FnMut<A>,
+    {
+        extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
+            (*self).call_mut(args)
+        }
+    }
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    impl<A: Tuple, F: ?Sized> FnOnce<A> for &mut F
+    where
+        F: FnMut<A>,
+    {
+        type Output = F::Output;
+        extern "rust-call" fn call_once(self, args: A) -> F::Output {
+            (*self).call_mut(args)
+        }
+    }
+}
diff --git a/src/test/codegen/avr/avr-func-addrspace.rs b/src/test/codegen/avr/avr-func-addrspace.rs
index a038dfe76f7..cbbcfad3ef4 100644
--- a/src/test/codegen/avr/avr-func-addrspace.rs
+++ b/src/test/codegen/avr/avr-func-addrspace.rs
@@ -19,6 +19,8 @@ pub trait Sized { }
 pub trait Copy { }
 #[lang = "receiver"]
 pub trait Receiver { }
+#[lang = "tuple_trait"]
+pub trait Tuple { }
 
 pub struct Result<T, E> { _a: T, _b: E }
 
@@ -29,7 +31,7 @@ impl Copy for &usize {}
 pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
 
 #[lang = "fn_once"]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: Tuple> {
     #[lang = "fn_once_output"]
     type Output;
 
@@ -37,24 +39,16 @@ pub trait FnOnce<Args> {
 }
 
 #[lang = "fn_mut"]
-pub trait FnMut<Args> : FnOnce<Args> {
+pub trait FnMut<Args: Tuple> : FnOnce<Args> {
     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
 }
 
 #[lang = "fn"]
-pub trait Fn<Args>: FnOnce<Args> {
+pub trait Fn<Args: Tuple>: FnOnce<Args> {
     /// Performs the call operation.
     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
 }
 
-impl<'a, A, R> FnOnce<A> for &'a fn(A) -> R {
-    type Output = R;
-
-    extern "rust-call" fn call_once(self, args: A) -> R {
-        (*self)(args)
-    }
-}
-
 pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
 pub static mut STORAGE_BAR: u32 = 12;
 
diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs
index ff79acc7f63..3121abbea36 100644
--- a/src/test/incremental/hashes/extern_mods.rs
+++ b/src/test/incremental/hashes/extern_mods.rs
@@ -128,7 +128,7 @@ extern "C" {
 // Change calling convention ---------------------------------------------------
 #[cfg(any(cfail1,cfail4))]
 extern "C" {
-    pub fn change_calling_convention(c: i32);
+    pub fn change_calling_convention(c: (i32,));
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
@@ -137,7 +137,7 @@ extern "C" {
 #[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail6")]
 extern "rust-call" {
-    pub fn change_calling_convention(c: i32);
+    pub fn change_calling_convention(c: (i32,));
 }
 
 // Make function public --------------------------------------------------------
diff --git a/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs
index 7f365ce2bba..ece4dea9aaf 100644
--- a/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs
+++ b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs
@@ -1,7 +1,8 @@
 #![feature(unsized_locals)]
 #![feature(unboxed_closures)]
+#![feature(tuple_trait)]
 
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: std::marker::Tuple> {
     type Output;
     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
 }
diff --git a/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs
index a78b897d194..94df2b0b83f 100644
--- a/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs
+++ b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs
@@ -1,7 +1,8 @@
 #![feature(unsized_locals)]
 #![feature(unboxed_closures)]
+#![feature(tuple_trait)]
 
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: std::marker::Tuple> {
     type Output;
     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
 }
diff --git a/src/test/ui/abi/issues/issue-22565-rust-call.rs b/src/test/ui/abi/issues/issue-22565-rust-call.rs
index a08e0bfb5e5..a572666c888 100644
--- a/src/test/ui/abi/issues/issue-22565-rust-call.rs
+++ b/src/test/ui/abi/issues/issue-22565-rust-call.rs
@@ -1,32 +1,31 @@
 #![feature(unboxed_closures)]
 
 extern "rust-call" fn b(_i: i32) {}
-//~^ ERROR functions with the "rust-call" ABI must take a single non-self argument that is a tuple
+//~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
 
 trait Tr {
     extern "rust-call" fn a();
+    //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
 
     extern "rust-call" fn b() {}
-    //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+    //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
 }
 
 struct Foo;
 
 impl Foo {
     extern "rust-call" fn bar() {}
-    //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+    //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
 }
 
 impl Tr for Foo {
     extern "rust-call" fn a() {}
-    //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+    //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
 }
 
-fn main () {
+fn main() {
     b(10);
-
     Foo::bar();
-
     <Foo as Tr>::a();
     <Foo as Tr>::b();
 }
diff --git a/src/test/ui/abi/issues/issue-22565-rust-call.stderr b/src/test/ui/abi/issues/issue-22565-rust-call.stderr
index 3eee10bc5e9..9d205b444fa 100644
--- a/src/test/ui/abi/issues/issue-22565-rust-call.stderr
+++ b/src/test/ui/abi/issues/issue-22565-rust-call.stderr
@@ -1,26 +1,33 @@
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
+error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
   --> $DIR/issue-22565-rust-call.rs:3:1
    |
 LL | extern "rust-call" fn b(_i: i32) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `i32`
 
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
-  --> $DIR/issue-22565-rust-call.rs:9:5
-   |
-LL |     extern "rust-call" fn b() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
-  --> $DIR/issue-22565-rust-call.rs:16:5
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+  --> $DIR/issue-22565-rust-call.rs:17:5
    |
 LL |     extern "rust-call" fn bar() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
-  --> $DIR/issue-22565-rust-call.rs:21:5
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+  --> $DIR/issue-22565-rust-call.rs:22:5
    |
 LL |     extern "rust-call" fn a() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+  --> $DIR/issue-22565-rust-call.rs:7:5
+   |
+LL |     extern "rust-call" fn a();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+  --> $DIR/issue-22565-rust-call.rs:10:5
+   |
+LL |     extern "rust-call" fn b() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/abi/rustcall-generic.rs b/src/test/ui/abi/rustcall-generic.rs
index 411c98e1031..6eaccc436b6 100644
--- a/src/test/ui/abi/rustcall-generic.rs
+++ b/src/test/ui/abi/rustcall-generic.rs
@@ -2,9 +2,9 @@
 // check-pass
 //[opt] compile-flags: -Zmir-opt-level=3
 
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
-extern "rust-call" fn foo<T>(_: T) {}
+extern "rust-call" fn foo<T: std::marker::Tuple>(_: T) {}
 
 fn main() {
     foo(());
diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs
index e2f016614bf..a3350024e75 100644
--- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs
+++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs
@@ -1,4 +1,4 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
 // Tests that we can't assign to or mutably borrow upvars from `Fn`
 // closures (issue #17780)
@@ -7,10 +7,10 @@ fn set(x: &mut usize) {
     *x = 5;
 }
 
-fn to_fn<A, F: Fn<A>>(f: F) -> F {
+fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
     f
 }
-fn to_fn_mut<A, F: FnMut<A>>(f: F) -> F {
+fn to_fn_mut<A: std::marker::Tuple, F: FnMut<A>>(f: F) -> F {
     f
 }
 
diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
index 093589ed092..a0eaf1f163b 100644
--- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
+++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
@@ -1,8 +1,8 @@
 error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-immutable-upvar-mutation.rs:21:27
    |
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         let _f = to_fn(|| x = 42);
    |                  ----- -- ^^^^^^ cannot assign
@@ -13,8 +13,8 @@ LL |         let _f = to_fn(|| x = 42);
 error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-immutable-upvar-mutation.rs:24:31
    |
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         let _g = to_fn(|| set(&mut y));
    |                  ----- --     ^^^^^^ cannot borrow as mutable
@@ -25,8 +25,8 @@ LL |         let _g = to_fn(|| set(&mut y));
 error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-immutable-upvar-mutation.rs:29:22
    |
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
 ...
 LL |             to_fn(|| z = 42);
    |             ----- -- ^^^^^^ cannot assign
@@ -37,8 +37,8 @@ LL |             to_fn(|| z = 42);
 error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-immutable-upvar-mutation.rs:36:32
    |
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         let _f = to_fn(move || x = 42);
    |                  ----- ------- ^^^^^^ cannot assign
@@ -49,8 +49,8 @@ LL |         let _f = to_fn(move || x = 42);
 error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-immutable-upvar-mutation.rs:39:36
    |
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         let _g = to_fn(move || set(&mut y));
    |                  ----- -------     ^^^^^^ cannot borrow as mutable
@@ -61,8 +61,8 @@ LL |         let _g = to_fn(move || set(&mut y));
 error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-immutable-upvar-mutation.rs:44:27
    |
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+   |                                              - change this to accept `FnMut` instead of `Fn`
 ...
 LL |             to_fn(move || z = 42);
    |             ----- ------- ^^^^^^ cannot assign
diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.rs b/src/test/ui/borrowck/borrowck-move-by-capture.rs
index f26edef17f3..6f0eb1870f3 100644
--- a/src/test/ui/borrowck/borrowck-move-by-capture.rs
+++ b/src/test/ui/borrowck/borrowck-move-by-capture.rs
@@ -1,7 +1,7 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
-fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
 
 pub fn main() {
     let bar: Box<_> = Box::new(3);
diff --git a/src/test/ui/c-variadic/issue-86053-1.stderr b/src/test/ui/c-variadic/issue-86053-1.stderr
index 60b379faf4e..075bd1fc488 100644
--- a/src/test/ui/c-variadic/issue-86053-1.stderr
+++ b/src/test/ui/c-variadic/issue-86053-1.stderr
@@ -66,8 +66,8 @@ LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize
    |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
-   | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
    |
 help: a trait with a similar name exists
    |
diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.rs b/src/test/ui/cannot-mutate-captured-non-mut-var.rs
index a83884acb1d..952dab25bf9 100644
--- a/src/test/ui/cannot-mutate-captured-non-mut-var.rs
+++ b/src/test/ui/cannot-mutate-captured-non-mut-var.rs
@@ -1,8 +1,8 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
 use std::io::Read;
 
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
 
 fn main() {
     let x = 1;
diff --git a/src/test/ui/chalkify/closure.rs b/src/test/ui/chalkify/closure.rs
index 81114d491d7..408e8802d86 100644
--- a/src/test/ui/chalkify/closure.rs
+++ b/src/test/ui/chalkify/closure.rs
@@ -1,4 +1,5 @@
-// check-fail
+// known-bug: unknown
+// FIXME(chalk): Chalk needs support for the Tuple trait
 // compile-flags: -Z chalk
 
 fn main() -> () {
@@ -25,7 +26,7 @@ fn main() -> () {
     let mut c = b;
 
     c();
-    b(); //~ ERROR
+    b(); // FIXME: reenable when this is fixed ~ ERROR
 
     // FIXME(chalk): this doesn't quite work
     /*
diff --git a/src/test/ui/chalkify/closure.stderr b/src/test/ui/chalkify/closure.stderr
index 515e0cf0142..bcee0cab96a 100644
--- a/src/test/ui/chalkify/closure.stderr
+++ b/src/test/ui/chalkify/closure.stderr
@@ -1,22 +1,80 @@
-error[E0382]: borrow of moved value: `b`
-  --> $DIR/closure.rs:28:5
+error[E0277]: `()` is not a tuple
+  --> $DIR/closure.rs:7:5
+   |
+LL |     t();
+   |     ^^^ the trait `Tuple` is not implemented for `()`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() -> () where (): Tuple {
+   |                 +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+  --> $DIR/closure.rs:13:5
+   |
+LL |     b();
+   |     ^^^ the trait `Tuple` is not implemented for `()`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() -> () where (): Tuple {
+   |                 +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+  --> $DIR/closure.rs:17:5
+   |
+LL |     c();
+   |     ^^^ the trait `Tuple` is not implemented for `()`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() -> () where (): Tuple {
+   |                 +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+  --> $DIR/closure.rs:18:5
    |
-LL |     let mut c = b;
-   |                 - value moved here
-...
 LL |     b();
-   |     ^ value borrowed here after move
+   |     ^^^ the trait `Tuple` is not implemented for `()`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() -> () where (): Tuple {
+   |                 +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+  --> $DIR/closure.rs:24:5
+   |
+LL |     b();
+   |     ^^^ the trait `Tuple` is not implemented for `()`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() -> () where (): Tuple {
+   |                 +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+  --> $DIR/closure.rs:28:5
+   |
+LL |     c();
+   |     ^^^ the trait `Tuple` is not implemented for `()`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() -> () where (): Tuple {
+   |                 +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+  --> $DIR/closure.rs:29:5
    |
-note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment
-  --> $DIR/closure.rs:21:9
+LL |     b(); // FIXME: reenable when this is fixed ~ ERROR
+   |     ^^^ the trait `Tuple` is not implemented for `()`
    |
-LL |         a = 1;
-   |         ^
-help: consider mutably borrowing `b`
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
-LL |     let mut c = &mut b;
-   |                 ++++
+LL | fn main() -> () where (): Tuple {
+   |                 +++++++++++++++
 
-error: aborting due to previous error
+error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0382`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/chalkify/trait-objects.rs b/src/test/ui/chalkify/trait-objects.rs
index d56abc42bf5..30929e943bd 100644
--- a/src/test/ui/chalkify/trait-objects.rs
+++ b/src/test/ui/chalkify/trait-objects.rs
@@ -1,4 +1,5 @@
-// check-pass
+// known-bug: unknown
+// FIXME(chalk): Chalk needs support for the Tuple trait
 // compile-flags: -Z chalk
 
 use std::fmt::Display;
diff --git a/src/test/ui/chalkify/trait-objects.stderr b/src/test/ui/chalkify/trait-objects.stderr
new file mode 100644
index 00000000000..098bd2d3226
--- /dev/null
+++ b/src/test/ui/chalkify/trait-objects.stderr
@@ -0,0 +1,28 @@
+error: the type `&dyn Fn(i32) -> _` is not well-formed (chalk)
+  --> $DIR/trait-objects.rs:11:12
+   |
+LL |     let f: &dyn Fn(i32) -> _ = &|x| x + x;
+   |            ^^^^^^^^^^^^^^^^^
+
+error[E0277]: `(i32,)` is not a tuple
+  --> $DIR/trait-objects.rs:12:5
+   |
+LL |     f(2);
+   |     ^^^^ the trait `Tuple` is not implemented for `(i32,)`
+   |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() where (i32,): Tuple {
+   |           +++++++++++++++++++
+
+error[E0277]: expected a `Fn<(i32,)>` closure, found `dyn Fn(i32) -> i32`
+  --> $DIR/trait-objects.rs:12:5
+   |
+LL |     f(2);
+   |     ^^^^ expected an `Fn<(i32,)>` closure, found `dyn Fn(i32) -> i32`
+   |
+   = help: the trait `Fn<(i32,)>` is not implemented for `dyn Fn(i32) -> i32`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/closures/issue-78720.stderr b/src/test/ui/closures/issue-78720.stderr
index 3dd13877298..da3f539a007 100644
--- a/src/test/ui/closures/issue-78720.stderr
+++ b/src/test/ui/closures/issue-78720.stderr
@@ -12,8 +12,8 @@ LL |     _func: F,
    |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
-   | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
    |
 help: a trait with a similar name exists
    |
diff --git a/src/test/ui/error-codes/E0059.stderr b/src/test/ui/error-codes/E0059.stderr
index a1b8aeaedbb..f331d014226 100644
--- a/src/test/ui/error-codes/E0059.stderr
+++ b/src/test/ui/error-codes/E0059.stderr
@@ -1,8 +1,14 @@
-error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit
-  --> $DIR/E0059.rs:3:41
+error[E0059]: type parameter to bare `Fn` trait must be a tuple
+  --> $DIR/E0059.rs:3:11
    |
 LL | fn foo<F: Fn<i32>>(f: F) -> F::Output { f(3) }
-   |                                         ^^^^
+   |           ^^^^^^^ the trait `Tuple` is not implemented for `i32`
+   |
+note: required by a bound in `Fn`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   |                    ^^^^^ required by this bound in `Fn`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-abi.rs b/src/test/ui/feature-gates/feature-gate-abi.rs
index 855263595d0..15b674c62e4 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.rs
+++ b/src/test/ui/feature-gates/feature-gate-abi.rs
@@ -9,6 +9,9 @@
 #[lang="sized"]
 trait Sized { }
 
+#[lang="tuple_trait"]
+trait Tuple { }
+
 // Functions
 extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
                                    //~^ ERROR intrinsic must be in
diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr
index bcca39c8fb8..33ec250f090 100644
--- a/src/test/ui/feature-gates/feature-gate-abi.stderr
+++ b/src/test/ui/feature-gates/feature-gate-abi.stderr
@@ -1,5 +1,5 @@
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:13:8
+  --> $DIR/feature-gate-abi.rs:16:8
    |
 LL | extern "rust-intrinsic" fn f1() {}
    |        ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | extern "rust-intrinsic" fn f1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:15:8
+  --> $DIR/feature-gate-abi.rs:18:8
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | extern "platform-intrinsic" fn f2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:17:8
+  --> $DIR/feature-gate-abi.rs:20:8
    |
 LL | extern "rust-call" fn f4(_: ()) {}
    |        ^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL | extern "rust-call" fn f4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:18:8
+  --> $DIR/feature-gate-abi.rs:21:8
    |
 LL | extern "efiapi" fn f10() {}
    |        ^^^^^^^^
@@ -34,7 +34,7 @@ LL | extern "efiapi" fn f10() {}
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:22:12
+  --> $DIR/feature-gate-abi.rs:25:12
    |
 LL |     extern "rust-intrinsic" fn m1();
    |            ^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ LL |     extern "rust-intrinsic" fn m1();
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:24:12
+  --> $DIR/feature-gate-abi.rs:27:12
    |
 LL |     extern "platform-intrinsic" fn m2();
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL |     extern "platform-intrinsic" fn m2();
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:26:12
+  --> $DIR/feature-gate-abi.rs:29:12
    |
 LL |     extern "rust-call" fn m4(_: ());
    |            ^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     extern "rust-call" fn m4(_: ());
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:27:12
+  --> $DIR/feature-gate-abi.rs:30:12
    |
 LL |     extern "efiapi" fn m10();
    |            ^^^^^^^^
@@ -69,7 +69,7 @@ LL |     extern "efiapi" fn m10();
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:29:12
+  --> $DIR/feature-gate-abi.rs:32:12
    |
 LL |     extern "rust-call" fn dm4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -78,7 +78,7 @@ LL |     extern "rust-call" fn dm4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:30:12
+  --> $DIR/feature-gate-abi.rs:33:12
    |
 LL |     extern "efiapi" fn dm10() {}
    |            ^^^^^^^^
@@ -87,7 +87,7 @@ LL |     extern "efiapi" fn dm10() {}
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:37:12
+  --> $DIR/feature-gate-abi.rs:40:12
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL |     extern "rust-intrinsic" fn m1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:39:12
+  --> $DIR/feature-gate-abi.rs:42:12
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@ LL |     extern "platform-intrinsic" fn m2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:41:12
+  --> $DIR/feature-gate-abi.rs:44:12
    |
 LL |     extern "rust-call" fn m4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -113,7 +113,7 @@ LL |     extern "rust-call" fn m4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:42:12
+  --> $DIR/feature-gate-abi.rs:45:12
    |
 LL |     extern "efiapi" fn m10() {}
    |            ^^^^^^^^
@@ -122,7 +122,7 @@ LL |     extern "efiapi" fn m10() {}
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:47:12
+  --> $DIR/feature-gate-abi.rs:50:12
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -130,7 +130,7 @@ LL |     extern "rust-intrinsic" fn im1() {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:49:12
+  --> $DIR/feature-gate-abi.rs:52:12
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL |     extern "platform-intrinsic" fn im2() {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:51:12
+  --> $DIR/feature-gate-abi.rs:54:12
    |
 LL |     extern "rust-call" fn im4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -148,7 +148,7 @@ LL |     extern "rust-call" fn im4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:52:12
+  --> $DIR/feature-gate-abi.rs:55:12
    |
 LL |     extern "efiapi" fn im10() {}
    |            ^^^^^^^^
@@ -157,7 +157,7 @@ LL |     extern "efiapi" fn im10() {}
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:56:18
+  --> $DIR/feature-gate-abi.rs:59:18
    |
 LL | type A1 = extern "rust-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL | type A1 = extern "rust-intrinsic" fn();
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:57:18
+  --> $DIR/feature-gate-abi.rs:60:18
    |
 LL | type A2 = extern "platform-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^^^^^
@@ -174,7 +174,7 @@ LL | type A2 = extern "platform-intrinsic" fn();
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:58:18
+  --> $DIR/feature-gate-abi.rs:61:18
    |
 LL | type A4 = extern "rust-call" fn(_: ());
    |                  ^^^^^^^^^^^
@@ -183,7 +183,7 @@ LL | type A4 = extern "rust-call" fn(_: ());
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:59:19
+  --> $DIR/feature-gate-abi.rs:62:19
    |
 LL | type A10 = extern "efiapi" fn();
    |                   ^^^^^^^^
@@ -192,7 +192,7 @@ LL | type A10 = extern "efiapi" fn();
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:62:8
+  --> $DIR/feature-gate-abi.rs:65:8
    |
 LL | extern "rust-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^
@@ -200,7 +200,7 @@ LL | extern "rust-intrinsic" {}
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:63:8
+  --> $DIR/feature-gate-abi.rs:66:8
    |
 LL | extern "platform-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +209,7 @@ LL | extern "platform-intrinsic" {}
    = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:64:8
+  --> $DIR/feature-gate-abi.rs:67:8
    |
 LL | extern "rust-call" {}
    |        ^^^^^^^^^^^
@@ -218,7 +218,7 @@ LL | extern "rust-call" {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0658]: efiapi ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:65:8
+  --> $DIR/feature-gate-abi.rs:68:8
    |
 LL | extern "efiapi" {}
    |        ^^^^^^^^
@@ -227,49 +227,49 @@ LL | extern "efiapi" {}
    = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:22:32
+  --> $DIR/feature-gate-abi.rs:25:32
    |
 LL |     extern "rust-intrinsic" fn m1();
    |                                ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:24:36
+  --> $DIR/feature-gate-abi.rs:27:36
    |
 LL |     extern "platform-intrinsic" fn m2();
    |                                    ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:13:33
+  --> $DIR/feature-gate-abi.rs:16:33
    |
 LL | extern "rust-intrinsic" fn f1() {}
    |                                 ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:15:37
+  --> $DIR/feature-gate-abi.rs:18:37
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:37:37
+  --> $DIR/feature-gate-abi.rs:40:37
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:39:41
+  --> $DIR/feature-gate-abi.rs:42:41
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |                                         ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:47:38
+  --> $DIR/feature-gate-abi.rs:50:38
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |                                      ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:49:42
+  --> $DIR/feature-gate-abi.rs:52:42
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |                                          ^^
diff --git a/src/test/ui/function-pointer/unsized-ret.rs b/src/test/ui/function-pointer/unsized-ret.rs
index 60af5769d6d..79009c5cb6c 100644
--- a/src/test/ui/function-pointer/unsized-ret.rs
+++ b/src/test/ui/function-pointer/unsized-ret.rs
@@ -1,7 +1,8 @@
 #![feature(fn_traits)]
 #![feature(unboxed_closures)]
+#![feature(tuple_trait)]
 
-fn foo<F: Fn<T>, T>(f: Option<F>, t: T) {
+fn foo<F: Fn<T>, T:std::marker::Tuple>(f: Option<F>, t: T) {
     let y = (f.unwrap()).call(t);
 }
 
diff --git a/src/test/ui/function-pointer/unsized-ret.stderr b/src/test/ui/function-pointer/unsized-ret.stderr
index bec3e2aa3fe..40bf7a3898a 100644
--- a/src/test/ui/function-pointer/unsized-ret.stderr
+++ b/src/test/ui/function-pointer/unsized-ret.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/unsized-ret.rs:9:27
+  --> $DIR/unsized-ret.rs:10:27
    |
 LL |     foo::<fn() -> str, _>(None, ());
    |     --------------------- ^^^^ doesn't have a size known at compile-time
@@ -9,13 +9,13 @@ LL |     foo::<fn() -> str, _>(None, ());
    = help: within `fn() -> str`, the trait `Sized` is not implemented for `str`
    = note: required because it appears within the type `fn() -> str`
 note: required by a bound in `foo`
-  --> $DIR/unsized-ret.rs:4:11
+  --> $DIR/unsized-ret.rs:5:11
    |
-LL | fn foo<F: Fn<T>, T>(f: Option<F>, t: T) {
+LL | fn foo<F: Fn<T>, T:std::marker::Tuple>(f: Option<F>, t: T) {
    |           ^^^^^ required by this bound in `foo`
 
 error[E0277]: the size for values of type `(dyn std::fmt::Display + 'a)` cannot be known at compilation time
-  --> $DIR/unsized-ret.rs:12:66
+  --> $DIR/unsized-ret.rs:13:66
    |
 LL |     foo::<for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a), _>(None, (&(),));
    |     ------------------------------------------------------------ ^^^^ doesn't have a size known at compile-time
@@ -25,9 +25,9 @@ LL |     foo::<for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a), _>(None, (&()
    = help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`
    = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`
 note: required by a bound in `foo`
-  --> $DIR/unsized-ret.rs:4:11
+  --> $DIR/unsized-ret.rs:5:11
    |
-LL | fn foo<F: Fn<T>, T>(f: Option<F>, t: T) {
+LL | fn foo<F: Fn<T>, T:std::marker::Tuple>(f: Option<F>, t: T) {
    |           ^^^^^ required by this bound in `foo`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-12127.rs b/src/test/ui/issues/issue-12127.rs
index 8b30ddc2de6..199d542e816 100644
--- a/src/test/ui/issues/issue-12127.rs
+++ b/src/test/ui/issues/issue-12127.rs
@@ -1,6 +1,6 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
 fn do_it(x: &isize) { }
 
 fn main() {
diff --git a/src/test/ui/issues/issue-23024.stderr b/src/test/ui/issues/issue-23024.stderr
index 73f93c51d34..dc8b34a70c3 100644
--- a/src/test/ui/issues/issue-23024.stderr
+++ b/src/test/ui/issues/issue-23024.stderr
@@ -16,7 +16,7 @@ LL |     println!("{:?}",(vfnfer[0] as dyn Fn)(3));
 note: trait defined here, with 1 generic parameter: `Args`
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
    |           ^^ ----
 help: add missing generic argument
    |
diff --git a/src/test/ui/issues/issue-7607-1.stderr b/src/test/ui/issues/issue-7607-1.stderr
index ecff8b42b0e..f1ab0ad26d7 100644
--- a/src/test/ui/issues/issue-7607-1.stderr
+++ b/src/test/ui/issues/issue-7607-1.stderr
@@ -6,8 +6,8 @@ LL | impl Fo {
    |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
-   | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lang-items/lang-item-missing-generator.rs b/src/test/ui/lang-items/lang-item-missing-generator.rs
index 0c329542928..9b9aff38e52 100644
--- a/src/test/ui/lang-items/lang-item-missing-generator.rs
+++ b/src/test/ui/lang-items/lang-item-missing-generator.rs
@@ -1,12 +1,14 @@
 // error-pattern: requires `generator` lang_item
-#![feature(no_core, lang_items, unboxed_closures)]
+#![feature(no_core, lang_items, unboxed_closures, tuple_trait)]
 #![no_core]
 
 #[lang = "sized"] pub trait Sized { }
 
+#[lang = "tuple_trait"] pub trait Tuple { }
+
 #[lang = "fn_once"]
 #[rustc_paren_sugar]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: Tuple> {
     type Output;
 
     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
diff --git a/src/test/ui/lang-items/lang-item-missing-generator.stderr b/src/test/ui/lang-items/lang-item-missing-generator.stderr
index fa13bf0b127..a24fdb5fb65 100644
--- a/src/test/ui/lang-items/lang-item-missing-generator.stderr
+++ b/src/test/ui/lang-items/lang-item-missing-generator.stderr
@@ -1,8 +1,15 @@
+error[E0635]: unknown feature `tuple_trait`
+  --> $DIR/lang-item-missing-generator.rs:2:51
+   |
+LL | #![feature(no_core, lang_items, unboxed_closures, tuple_trait)]
+   |                                                   ^^^^^^^^^^^
+
 error: requires `generator` lang_item
-  --> $DIR/lang-item-missing-generator.rs:15:17
+  --> $DIR/lang-item-missing-generator.rs:17:17
    |
 LL | pub fn abc() -> impl FnOnce(f32) {
    |                 ^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0635`.
diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs
index 8dbe3472ea8..307104e47a1 100644
--- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs
+++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs
@@ -1,8 +1,8 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures,tuple_trait)]
 
 use std::ops::FnMut;
 
-fn to_fn_mut<A, F: FnMut<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple, F:FnMut<A>>(f: F) -> F { f }
 
 fn call_it<F: FnMut(isize, isize) -> isize>(y: isize, mut f: F) -> isize {
     //~^ NOTE required by this bound in `call_it`
diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
index 76b7aab542d..490d91ac118 100644
--- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
+++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
@@ -1,6 +1,6 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
-fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
 
 fn test(_x: Box<usize>) {}
 
diff --git a/src/test/ui/overloaded/overloaded-calls-nontuple.rs b/src/test/ui/overloaded/overloaded-calls-nontuple.rs
index 07d44ff82b1..32a3b93e0a1 100644
--- a/src/test/ui/overloaded/overloaded-calls-nontuple.rs
+++ b/src/test/ui/overloaded/overloaded-calls-nontuple.rs
@@ -8,22 +8,23 @@ struct S {
 }
 
 impl FnMut<isize> for S {
+    //~^ ERROR type parameter to bare `FnMut` trait must be a tuple
     extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
+        //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
         self.x + self.y + z
     }
-    //~^^^ ERROR functions with the "rust-call" ABI must take a single non-self argument
 }
 
 impl FnOnce<isize> for S {
+    //~^ ERROR type parameter to bare `FnOnce` trait must be a tuple
     type Output = isize;
-    extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
-    //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+    extern "rust-call" fn call_once(mut self, z: isize) -> isize {
+        //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
+        self.call_mut(z)
+    }
 }
 
 fn main() {
-    let mut s = S {
-        x: 1,
-        y: 2,
-    };
-    drop(s(3))  //~ ERROR cannot use call notation
+    let mut s = S { x: 1, y: 2 };
+    drop(s(3))
 }
diff --git a/src/test/ui/overloaded/overloaded-calls-nontuple.stderr b/src/test/ui/overloaded/overloaded-calls-nontuple.stderr
index 8f299bc9434..794535aeb11 100644
--- a/src/test/ui/overloaded/overloaded-calls-nontuple.stderr
+++ b/src/test/ui/overloaded/overloaded-calls-nontuple.stderr
@@ -1,21 +1,40 @@
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
-  --> $DIR/overloaded-calls-nontuple.rs:11:5
+error[E0059]: type parameter to bare `FnMut` trait must be a tuple
+  --> $DIR/overloaded-calls-nontuple.rs:10:6
    |
-LL |     extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl FnMut<isize> for S {
+   |      ^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize`
+   |
+note: required by a bound in `FnMut`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait FnMut<Args: Tuple>: FnOnce<Args> {
+   |                       ^^^^^ required by this bound in `FnMut`
+
+error[E0059]: type parameter to bare `FnOnce` trait must be a tuple
+  --> $DIR/overloaded-calls-nontuple.rs:18:6
+   |
+LL | impl FnOnce<isize> for S {
+   |      ^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize`
+   |
+note: required by a bound in `FnOnce`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait FnOnce<Args: Tuple> {
+   |                        ^^^^^ required by this bound in `FnOnce`
 
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
-  --> $DIR/overloaded-calls-nontuple.rs:19:5
+error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
+  --> $DIR/overloaded-calls-nontuple.rs:12:5
    |
-LL |     extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize`
 
-error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit
-  --> $DIR/overloaded-calls-nontuple.rs:28:10
+error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
+  --> $DIR/overloaded-calls-nontuple.rs:21:5
    |
-LL |     drop(s(3))
-   |          ^^^^
+LL |     extern "rust-call" fn call_once(mut self, z: isize) -> isize {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0059`.
+Some errors have detailed explanations: E0059, E0277.
+For more information about an error, try `rustc --explain E0059`.
diff --git a/src/test/ui/parser/kw-in-trait-bounds.stderr b/src/test/ui/parser/kw-in-trait-bounds.stderr
index 28196c7ce2d..546ad84eeee 100644
--- a/src/test/ui/parser/kw-in-trait-bounds.stderr
+++ b/src/test/ui/parser/kw-in-trait-bounds.stderr
@@ -94,8 +94,8 @@ LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
    |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
-   | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
 
 error[E0405]: cannot find trait `r#fn` in this scope
   --> $DIR/kw-in-trait-bounds.rs:17:4
@@ -105,8 +105,8 @@ LL | G: fn(),
    |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
-   | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
 
 error[E0405]: cannot find trait `r#fn` in this scope
   --> $DIR/kw-in-trait-bounds.rs:3:27
@@ -116,8 +116,8 @@ LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
    |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
-   | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
 
 error[E0405]: cannot find trait `r#fn` in this scope
   --> $DIR/kw-in-trait-bounds.rs:3:41
@@ -127,8 +127,8 @@ LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
    |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
-   | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
 
 error[E0405]: cannot find trait `r#struct` in this scope
   --> $DIR/kw-in-trait-bounds.rs:24:10
diff --git a/src/test/ui/span/issue-11925.rs b/src/test/ui/span/issue-11925.rs
index d9c08fbdd0f..cac9fd5bfb6 100644
--- a/src/test/ui/span/issue-11925.rs
+++ b/src/test/ui/span/issue-11925.rs
@@ -1,6 +1,6 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
 
 fn main() {
     let r = {
diff --git a/src/test/ui/typeck/issue-83693.stderr b/src/test/ui/typeck/issue-83693.stderr
index 0d8bbf1ce98..1e45c2d35df 100644
--- a/src/test/ui/typeck/issue-83693.stderr
+++ b/src/test/ui/typeck/issue-83693.stderr
@@ -6,8 +6,8 @@ LL | impl F {
    |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
-LL | pub trait Fn<Args>: FnMut<Args> {
-   | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   | -------------------------------------- similarly named trait `Fn` defined here
 
 error[E0412]: cannot find type `TestResult` in this scope
   --> $DIR/issue-83693.rs:9:22
diff --git a/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs
index 925463d6dee..d2e48600227 100644
--- a/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs
+++ b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs
@@ -1,8 +1,8 @@
 #![feature(unboxed_closures)]
 
 fn a<F: Fn<usize>>(f: F) {}
+//~^ ERROR type parameter to bare `Fn` trait must be a tuple
 
 fn main() {
     a(|_: usize| {});
-    //~^ ERROR mismatched types
 }
diff --git a/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr
index 9a24fb8c2be..1c18eb0fc49 100644
--- a/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr
+++ b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr
@@ -1,17 +1,15 @@
-error[E0308]: mismatched types
-  --> $DIR/non-tupled-arg-mismatch.rs:6:5
-   |
-LL |     a(|_: usize| {});
-   |     ^ types differ
-   |
-   = note: expected trait `Fn<usize>`
-              found trait `Fn<(usize,)>`
-note: required by a bound in `a`
+error[E0059]: type parameter to bare `Fn` trait must be a tuple
   --> $DIR/non-tupled-arg-mismatch.rs:3:9
    |
 LL | fn a<F: Fn<usize>>(f: F) {}
-   |         ^^^^^^^^^ required by this bound in `a`
+   |         ^^^^^^^^^ the trait `Tuple` is not implemented for `usize`
+   |
+note: required by a bound in `Fn`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+   |                    ^^^^^ required by this bound in `Fn`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0059`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.rs b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.rs
index ed8d7211461..7377359b6b0 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.rs
@@ -1,12 +1,12 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
 // Tests that we can't move out of an unboxed closure environment
 // if the upvar is captured by ref or the closure takes self by
 // reference.
 
-fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
-fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
 
 fn main() {
     // By-ref cases
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs
index 57e6d30658c..c57312b4387 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.rs
@@ -2,12 +2,12 @@
 // as `mut` through a closure. Also test that we CAN mutate a moved copy,
 // unless this is a `Fn` closure. Issue #16749.
 
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
 use std::mem;
 
-fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
-fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
 
 fn a() {
     let n = 0;
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
index d6e74b5b8b9..26f97b51913 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
@@ -28,8 +28,8 @@ LL |         n += 1;
 error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure
   --> $DIR/unboxed-closures-mutate-upvar.rs:53:9
    |
-LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
-   |                        - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+   |                                           - change this to accept `FnMut` instead of `Fn`
 ...
 LL |     let mut f = to_fn(move || {
    |                 ----- ------- in this closure
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs
index 0e727b11cd2..7289d9322d0 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.rs
@@ -1,6 +1,6 @@
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
 
-fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
 
 fn main() {
     let mut_ = to_fn_mut(|x| x);